Unify buttons (#8865)
* Unity buttons * Fix texts and use defineMessages * Update snapshots * Fix disabled style
This commit is contained in:
parent
705ed603bc
commit
2ad6fec90f
31 changed files with 661 additions and 821 deletions
|
|
@ -2,14 +2,13 @@
|
|||
// See LICENSE.txt for license information.
|
||||
|
||||
import {BottomSheetScrollView} from '@gorhom/bottom-sheet';
|
||||
import {Button} from '@rneui/base';
|
||||
import React, {useCallback, useMemo} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {ScrollView, Text, View} from 'react-native';
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context';
|
||||
|
||||
import {dismissAnnouncement} from '@actions/local/systems';
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import Button from '@components/button';
|
||||
import Markdown from '@components/markdown';
|
||||
import {Screens} from '@constants';
|
||||
import {useServerUrl} from '@context/server';
|
||||
|
|
@ -17,7 +16,6 @@ import {useTheme} from '@context/theme';
|
|||
import {useBottomSheetListsFix} from '@hooks/bottom_sheet_lists_fix';
|
||||
import {useIsTablet} from '@hooks/device';
|
||||
import {dismissBottomSheet} from '@screens/navigation';
|
||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||
import {getMarkdownTextStyles, getMarkdownBlockStyles} from '@utils/markdown';
|
||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {typography} from '@utils/typography';
|
||||
|
|
@ -46,6 +44,9 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
|||
color: theme.centerChannelColor,
|
||||
...typography('Heading', 600, 'SemiBold'),
|
||||
},
|
||||
dismissButtonContainer: {
|
||||
marginTop: 10,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
|
|
@ -69,20 +70,7 @@ const ExpandedAnnouncementBanner = ({
|
|||
const dismissBanner = useCallback(() => {
|
||||
dismissAnnouncement(serverUrl, bannerText);
|
||||
close();
|
||||
}, [bannerText]);
|
||||
|
||||
const buttonStyles = useMemo(() => {
|
||||
return {
|
||||
okay: {
|
||||
button: buttonBackgroundStyle(theme, 'lg', 'primary'),
|
||||
text: buttonTextStyle(theme, 'lg', 'primary'),
|
||||
},
|
||||
dismiss: {
|
||||
button: [{marginTop: 10}, buttonBackgroundStyle(theme, 'lg', 'link')],
|
||||
text: buttonTextStyle(theme, 'lg', 'link'),
|
||||
},
|
||||
};
|
||||
}, [theme]);
|
||||
}, [bannerText, serverUrl]);
|
||||
|
||||
const containerStyle = useMemo(() => {
|
||||
return [style.container, {marginBottom: insets.bottom + 10}];
|
||||
|
|
@ -118,26 +106,21 @@ const ExpandedAnnouncementBanner = ({
|
|||
/>
|
||||
</Scroll>
|
||||
<Button
|
||||
buttonStyle={buttonStyles.okay.button}
|
||||
text={intl.formatMessage({id: 'announcment_banner.okay', defaultMessage: 'Okay'})}
|
||||
onPress={close}
|
||||
>
|
||||
<FormattedText
|
||||
id='announcment_banner.okay'
|
||||
defaultMessage={'Okay'}
|
||||
style={buttonStyles.okay.text}
|
||||
size='lg'
|
||||
theme={theme}
|
||||
/>
|
||||
</Button>
|
||||
{allowDismissal && (
|
||||
<View style={style.dismissButtonContainer}>
|
||||
<Button
|
||||
buttonStyle={buttonStyles.dismiss.button}
|
||||
text={intl.formatMessage({id: 'announcment_banner.dismiss', defaultMessage: 'Dismiss announcement'})}
|
||||
onPress={dismissBanner}
|
||||
>
|
||||
<FormattedText
|
||||
id='announcment_banner.dismiss'
|
||||
defaultMessage={'Dismiss announcement'}
|
||||
style={buttonStyles.dismiss.text}
|
||||
size='lg'
|
||||
theme={theme}
|
||||
emphasis='link'
|
||||
/>
|
||||
</Button>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import React, {useMemo, type ReactNode} from 'react';
|
|||
import {type StyleProp, StyleSheet, Text, type TextStyle, View, type ViewStyle, type Insets} from 'react-native';
|
||||
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import Loading from '@components/loading';
|
||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||
import {changeOpacity} from '@utils/theme';
|
||||
|
||||
type Props = {
|
||||
theme: Theme;
|
||||
|
|
@ -16,16 +16,17 @@ type Props = {
|
|||
textStyle?: StyleProp<TextStyle>;
|
||||
size?: ButtonSize;
|
||||
emphasis?: ButtonEmphasis;
|
||||
buttonType?: ButtonType;
|
||||
buttonState?: ButtonState;
|
||||
testID?: string;
|
||||
onPress: () => void;
|
||||
onPress?: () => void;
|
||||
text: string;
|
||||
iconComponent?: ReactNode;
|
||||
disabled?: boolean;
|
||||
hitSlop?: Insets;
|
||||
isIconOnTheRight?: boolean;
|
||||
iconName?: string;
|
||||
showLoader?: boolean;
|
||||
isInverted?: boolean;
|
||||
isDestructive?: boolean;
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
|
@ -50,8 +51,6 @@ const Button = ({
|
|||
textStyle,
|
||||
size = 'm',
|
||||
emphasis,
|
||||
buttonType,
|
||||
buttonState,
|
||||
onPress,
|
||||
text,
|
||||
testID,
|
||||
|
|
@ -60,24 +59,44 @@ const Button = ({
|
|||
iconComponent,
|
||||
disabled,
|
||||
hitSlop,
|
||||
showLoader = false,
|
||||
isInverted = false,
|
||||
isDestructive = false,
|
||||
}: Props) => {
|
||||
const bgStyle = useMemo(() => [
|
||||
buttonBackgroundStyle(theme, size, emphasis, buttonType, buttonState),
|
||||
backgroundStyle,
|
||||
], [theme, backgroundStyle, size, emphasis, buttonType, buttonState]);
|
||||
let buttonType: ButtonType = 'default';
|
||||
if (isDestructive) {
|
||||
buttonType = 'destructive';
|
||||
} else if (isInverted) {
|
||||
buttonType = 'inverted';
|
||||
}
|
||||
|
||||
const txtStyle = useMemo(() => [
|
||||
const bgStyle = useMemo(() => [
|
||||
buttonBackgroundStyle(theme, size, emphasis, buttonType),
|
||||
backgroundStyle,
|
||||
], [theme, backgroundStyle, size, emphasis, buttonType]);
|
||||
|
||||
const bgDisabledStyle = useMemo(() => [
|
||||
buttonBackgroundStyle(theme, size, emphasis, 'disabled'),
|
||||
backgroundStyle,
|
||||
], [theme, backgroundStyle, size, emphasis]);
|
||||
|
||||
const txtStyle = useMemo(() => StyleSheet.flatten([
|
||||
buttonTextStyle(theme, size, emphasis, buttonType),
|
||||
textStyle,
|
||||
], [theme, textStyle, size, emphasis, buttonType]);
|
||||
]), [theme, textStyle, size, emphasis, buttonType]);
|
||||
|
||||
let buttonStyle = StyleSheet.flatten(bgStyle);
|
||||
if (disabled) {
|
||||
buttonStyle = {
|
||||
...buttonStyle,
|
||||
backgroundColor: changeOpacity(buttonStyle.backgroundColor! as string, 0.4),
|
||||
};
|
||||
}
|
||||
const txtDisabledStyle = useMemo(() => StyleSheet.flatten([
|
||||
buttonTextStyle(theme, size, emphasis, 'disabled'),
|
||||
textStyle,
|
||||
]), [theme, textStyle, size, emphasis]);
|
||||
|
||||
const txtStyleToUse = disabled ? txtDisabledStyle : txtStyle;
|
||||
|
||||
const loadingComponent = (
|
||||
<Loading
|
||||
color={txtStyleToUse.color}
|
||||
/>
|
||||
);
|
||||
|
||||
let icon: ReactNode;
|
||||
|
||||
|
|
@ -90,7 +109,7 @@ const Button = ({
|
|||
<CompassIcon
|
||||
name={iconName!}
|
||||
size={iconSizePerSize[size]}
|
||||
color={StyleSheet.flatten(txtStyle).color}
|
||||
color={txtStyleToUse.color}
|
||||
testID={`${testID}-icon`}
|
||||
/>
|
||||
</View>
|
||||
|
|
@ -99,8 +118,9 @@ const Button = ({
|
|||
|
||||
return (
|
||||
<ElementButton
|
||||
buttonStyle={buttonStyle}
|
||||
buttonStyle={bgStyle}
|
||||
containerStyle={buttonContainerStyle}
|
||||
disabledStyle={bgDisabledStyle}
|
||||
onPress={onPress}
|
||||
testID={testID}
|
||||
disabled={disabled}
|
||||
|
|
@ -110,9 +130,10 @@ const Button = ({
|
|||
style={styles.container}
|
||||
testID={`${testID}-text-container`}
|
||||
>
|
||||
{showLoader && loadingComponent}
|
||||
{!isIconOnTheRight && icon}
|
||||
<Text
|
||||
style={[txtStyle]}
|
||||
style={txtStyleToUse}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{text}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@
|
|||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {ActivityIndicator, type StyleProp, View, type ViewStyle, Text, type TextStyle} from 'react-native';
|
||||
import {ActivityIndicator, type StyleProp, View, type ViewStyle, Text, type TextStyle, type ColorValue} from 'react-native';
|
||||
|
||||
import {useTheme} from '@context/theme';
|
||||
|
||||
type LoadingProps = {
|
||||
containerStyle?: StyleProp<ViewStyle>;
|
||||
size?: number | 'small' | 'large';
|
||||
color?: string;
|
||||
color?: ColorValue;
|
||||
themeColor?: keyof Theme;
|
||||
footerText?: string;
|
||||
footerTextStyles?: TextStyle;
|
||||
|
|
|
|||
|
|
@ -73,11 +73,34 @@ exports[`Loading Error should match snapshot 1`] = `
|
|||
Error description
|
||||
</Text>
|
||||
<View
|
||||
style={
|
||||
{
|
||||
"marginTop": 24,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
[
|
||||
{
|
||||
"overflow": "hidden",
|
||||
},
|
||||
{
|
||||
"borderRadius": 2,
|
||||
},
|
||||
undefined,
|
||||
false,
|
||||
]
|
||||
}
|
||||
testID="RNE_BUTTON_WRAPPER"
|
||||
>
|
||||
<View
|
||||
accessibilityRole="button"
|
||||
accessibilityState={
|
||||
{
|
||||
"busy": undefined,
|
||||
"busy": false,
|
||||
"checked": undefined,
|
||||
"disabled": undefined,
|
||||
"disabled": false,
|
||||
"expanded": undefined,
|
||||
"selected": undefined,
|
||||
}
|
||||
|
|
@ -102,32 +125,54 @@ exports[`Loading Error should match snapshot 1`] = `
|
|||
onStartShouldSetResponder={[Function]}
|
||||
style={
|
||||
{
|
||||
"backgroundColor": "#ffffff",
|
||||
"borderRadius": 4,
|
||||
"marginTop": 24,
|
||||
"opacity": 1,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
{
|
||||
"alignItems": "center",
|
||||
"backgroundColor": "#1c58d9",
|
||||
"borderColor": "#2089dc",
|
||||
"borderRadius": 4,
|
||||
"borderWidth": 0,
|
||||
"flexDirection": "row",
|
||||
"justifyContent": "center",
|
||||
"padding": 8,
|
||||
"paddingHorizontal": 24,
|
||||
"paddingVertical": 12,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
<View
|
||||
style={
|
||||
[
|
||||
{
|
||||
"alignItems": "center",
|
||||
"flexDirection": "row",
|
||||
"gap": 7,
|
||||
}
|
||||
}
|
||||
testID="undefined-text-container"
|
||||
>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={
|
||||
{
|
||||
"color": "#ffffff",
|
||||
"fontFamily": "OpenSans-SemiBold",
|
||||
"fontSize": 16,
|
||||
"fontWeight": "600",
|
||||
"lineHeight": 24,
|
||||
},
|
||||
{
|
||||
"color": "#1c58d9",
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
>
|
||||
Retry
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useMemo} from 'react';
|
||||
import React from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {Text, View} from 'react-native';
|
||||
|
||||
import Button from '@components/button';
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import Loading from '@components/loading';
|
||||
import TouchableWithFeedback from '@components/touchable_with_feedback';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {typography} from '@utils/typography';
|
||||
|
||||
|
|
@ -49,14 +49,15 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
|||
textAlign: 'center',
|
||||
marginTop: 4,
|
||||
},
|
||||
buttonContainer: {
|
||||
marginTop: 24,
|
||||
},
|
||||
}));
|
||||
|
||||
const LoadingError = ({loading, message, onRetry, title}: Props) => {
|
||||
const theme = useTheme();
|
||||
const intl = useIntl();
|
||||
const styles = getStyleSheet(theme);
|
||||
const buttonStyle = useMemo(() => {
|
||||
return [{marginTop: 24}, buttonBackgroundStyle(theme, 'lg', 'primary', 'inverted')];
|
||||
}, [theme]);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
|
|
@ -81,13 +82,14 @@ const LoadingError = ({loading, message, onRetry, title}: Props) => {
|
|||
<Text style={[typography('Body', 200), styles.body]}>
|
||||
{message}
|
||||
</Text>
|
||||
<TouchableWithFeedback
|
||||
style={buttonStyle}
|
||||
<View style={styles.buttonContainer}>
|
||||
<Button
|
||||
text={intl.formatMessage({id: 'loading_error.retry', defaultMessage: 'Retry'})}
|
||||
onPress={onRetry}
|
||||
type={'opacity'}
|
||||
>
|
||||
<Text style={buttonTextStyle(theme, 'lg', 'primary', 'inverted')}>{'Retry'}</Text>
|
||||
</TouchableWithFeedback>
|
||||
size='lg'
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -186,22 +186,13 @@ exports[`Section notice match snapshot 1`] = `
|
|||
<Text
|
||||
numberOfLines={1}
|
||||
style={
|
||||
[
|
||||
[
|
||||
[
|
||||
{
|
||||
"color": "#ffffff",
|
||||
"fontFamily": "OpenSans-SemiBold",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
"lineHeight": 20,
|
||||
},
|
||||
{
|
||||
"color": "#ffffff",
|
||||
},
|
||||
],
|
||||
undefined,
|
||||
],
|
||||
]
|
||||
}
|
||||
}
|
||||
>
|
||||
primary button
|
||||
|
|
@ -297,22 +288,13 @@ exports[`Section notice match snapshot 1`] = `
|
|||
<Text
|
||||
numberOfLines={1}
|
||||
style={
|
||||
[
|
||||
[
|
||||
[
|
||||
{
|
||||
"color": "#1c58d9",
|
||||
"fontFamily": "OpenSans-SemiBold",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
"lineHeight": 20,
|
||||
},
|
||||
{
|
||||
"color": "#1c58d9",
|
||||
},
|
||||
],
|
||||
undefined,
|
||||
],
|
||||
]
|
||||
}
|
||||
}
|
||||
>
|
||||
secondary button
|
||||
|
|
@ -408,22 +390,13 @@ exports[`Section notice match snapshot 1`] = `
|
|||
<Text
|
||||
numberOfLines={1}
|
||||
style={
|
||||
[
|
||||
[
|
||||
[
|
||||
{
|
||||
"color": "#1c58d9",
|
||||
"fontFamily": "OpenSans-SemiBold",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
"lineHeight": 20,
|
||||
},
|
||||
{
|
||||
"color": "#1c58d9",
|
||||
},
|
||||
],
|
||||
undefined,
|
||||
],
|
||||
]
|
||||
}
|
||||
}
|
||||
>
|
||||
link button
|
||||
|
|
|
|||
|
|
@ -270,10 +270,10 @@ export default function SelectedUsers({
|
|||
iconName={buttonIcon}
|
||||
text={buttonText}
|
||||
theme={theme}
|
||||
buttonType={isDisabled ? 'disabled' : 'default'}
|
||||
emphasis={'primary'}
|
||||
size={'lg'}
|
||||
testID={`${testID}.start.button`}
|
||||
disabled={isDisabled}
|
||||
/>
|
||||
</Animated.View>
|
||||
</Animated.View>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Button} from '@rneui/base';
|
||||
import React, {useCallback, useEffect, useMemo, useReducer, useRef, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {Keyboard, ScrollView, Text, View} from 'react-native';
|
||||
import {Keyboard, ScrollView, View} from 'react-native';
|
||||
import {SafeAreaView} from 'react-native-safe-area-context';
|
||||
|
||||
import {handleGotoLocation} from '@actions/remote/command';
|
||||
import Button from '@components/button';
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import Markdown from '@components/markdown';
|
||||
import {Screens} from '@constants';
|
||||
|
|
@ -18,7 +18,6 @@ import useDidUpdate from '@hooks/did_update';
|
|||
import useNavButtonPressed from '@hooks/navigation_button_pressed';
|
||||
import SecurityManager from '@managers/security_manager';
|
||||
import {filterEmptyOptions} from '@utils/apps';
|
||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||
import {checkDialogElementForError, checkIfErrorsMatchElements} from '@utils/integrations';
|
||||
import {getMarkdownBlockStyles, getMarkdownTextStyles} from '@utils/markdown';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
|
@ -383,9 +382,6 @@ function AppsFormComponent({
|
|||
useNavButtonPressed(CLOSE_BUTTON_ID, componentId, close, [close]);
|
||||
useNavButtonPressed(SUBMIT_BUTTON_ID, componentId, handleSubmit, [handleSubmit]);
|
||||
|
||||
const submitButtonStyle = useMemo(() => buttonBackgroundStyle(theme, 'lg', 'primary', 'default'), [theme]);
|
||||
const submitButtonTextStyle = useMemo(() => buttonTextStyle(theme, 'lg', 'primary', 'default'), [theme]);
|
||||
|
||||
return (
|
||||
<SafeAreaView
|
||||
testID='interactive_dialog.screen'
|
||||
|
|
@ -444,10 +440,10 @@ function AppsFormComponent({
|
|||
>
|
||||
<Button
|
||||
onPress={() => handleSubmit(o.value)}
|
||||
buttonStyle={submitButtonStyle}
|
||||
>
|
||||
<Text style={submitButtonTextStyle}>{o.label}</Text>
|
||||
</Button>
|
||||
theme={theme}
|
||||
size='lg'
|
||||
text={o.label || ''}
|
||||
/>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -2,18 +2,16 @@
|
|||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {type GestureResponderEvent, Platform, Text, useWindowDimensions, View} from 'react-native';
|
||||
import {Platform, useWindowDimensions, View} from 'react-native';
|
||||
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import TouchableWithFeedback from '@components/touchable_with_feedback';
|
||||
import Button from '@components/button';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {useIsTablet} from '@hooks/device';
|
||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
type Props = {
|
||||
disabled?: boolean;
|
||||
onPress?: (e: GestureResponderEvent) => void;
|
||||
onPress?: () => void;
|
||||
icon?: string;
|
||||
testID?: string;
|
||||
text?: string;
|
||||
|
|
@ -21,22 +19,12 @@ type Props = {
|
|||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||
return {
|
||||
button: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
},
|
||||
buttonContainer: {
|
||||
paddingHorizontal: 20,
|
||||
},
|
||||
container: {
|
||||
backgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
iconContainer: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
top: -1,
|
||||
marginRight: 4,
|
||||
},
|
||||
separator: {
|
||||
height: 1,
|
||||
right: 20,
|
||||
|
|
@ -56,41 +44,23 @@ function BottomSheetButton({disabled = false, onPress, icon, testID, text}: Prop
|
|||
const styles = getStyleSheet(theme);
|
||||
|
||||
const separatorWidth = Math.max(dimensions.width, 450);
|
||||
const buttonType = disabled ? 'disabled' : 'default';
|
||||
const styleButtonText = buttonTextStyle(theme, 'lg', 'primary', buttonType);
|
||||
const styleButtonBackground = buttonBackgroundStyle(theme, 'lg', 'primary', buttonType);
|
||||
|
||||
const iconColor = disabled ? changeOpacity(theme.centerChannelColor, 0.32) : theme.buttonColor;
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={[styles.separator, {width: separatorWidth}]}/>
|
||||
<View style={styles.buttonContainer}>
|
||||
<TouchableWithFeedback
|
||||
<Button
|
||||
onPress={onPress}
|
||||
type='opacity'
|
||||
style={[styles.button, styleButtonBackground]}
|
||||
text={text || ''}
|
||||
iconName={icon}
|
||||
testID={testID}
|
||||
>
|
||||
{icon && (
|
||||
<View style={styles.iconContainer}>
|
||||
<CompassIcon
|
||||
size={24}
|
||||
name={icon}
|
||||
color={iconColor}
|
||||
theme={theme}
|
||||
size='lg'
|
||||
disabled={disabled}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
{text && (
|
||||
<Text
|
||||
style={styleButtonText}
|
||||
>{text}</Text>
|
||||
)}
|
||||
|
||||
</TouchableWithFeedback>
|
||||
<View style={{paddingBottom: Platform.select({ios: (isTablet ? 20 : 0), android: 20})}}/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {type GestureResponderEvent, Text, useWindowDimensions, View} from 'react-native';
|
||||
import {Text, useWindowDimensions, View} from 'react-native';
|
||||
|
||||
import {useTheme} from '@context/theme';
|
||||
import {useIsTablet} from '@hooks/device';
|
||||
|
|
@ -15,7 +15,7 @@ type Props = {
|
|||
buttonText?: string;
|
||||
children: React.ReactNode;
|
||||
disableButton?: boolean;
|
||||
onPress?: (e: GestureResponderEvent) => void;
|
||||
onPress?: () => void;
|
||||
showButton: boolean;
|
||||
showTitle: boolean;
|
||||
testID?: string;
|
||||
|
|
|
|||
|
|
@ -303,7 +303,6 @@ const ChannelBookmarkAddOrEdit = ({
|
|||
{canDeleteBookmarks &&
|
||||
<View style={styles.deleteContainer}>
|
||||
<Button
|
||||
buttonType='destructive'
|
||||
size='m'
|
||||
text='Delete bookmark'
|
||||
iconName='trash-can-outline'
|
||||
|
|
@ -311,6 +310,7 @@ const ChannelBookmarkAddOrEdit = ({
|
|||
onPress={onDelete}
|
||||
theme={theme}
|
||||
disabled={isSaving}
|
||||
isDestructive={true}
|
||||
/>
|
||||
</View>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,6 @@ const MutedBanner = ({channelId}: Props) => {
|
|||
/>
|
||||
<View style={styles.button}>
|
||||
<Button
|
||||
buttonType='default'
|
||||
onPress={onPress}
|
||||
text={formatMessage({
|
||||
id: 'channel_notification_preferences.unmute_content',
|
||||
|
|
|
|||
|
|
@ -7,14 +7,13 @@ import {Text, View} from 'react-native';
|
|||
|
||||
import {convertGroupMessageToPrivateChannel, switchToChannelById} from '@actions/remote/channel';
|
||||
import Button from '@components/button';
|
||||
import Loading from '@components/loading';
|
||||
import {ServerErrors} from '@constants';
|
||||
import {useServerUrl} from '@context/server';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {isErrorWithMessage, isServerError} from '@utils/errors';
|
||||
import {logError} from '@utils/log';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {displayUsername} from '@utils/user';
|
||||
|
||||
import {ChannelNameInput} from '../channel_name_input';
|
||||
|
|
@ -135,13 +134,6 @@ export const ConvertGMToChannelForm = ({
|
|||
memberNames,
|
||||
});
|
||||
|
||||
const buttonIcon = conversionInProgress ? (
|
||||
<Loading
|
||||
containerStyle={styles.loadingContainerStyle}
|
||||
color={changeOpacity(theme.centerChannelColor, 0.32)}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<MessageBox
|
||||
|
|
@ -164,9 +156,10 @@ export const ConvertGMToChannelForm = ({
|
|||
onPress={handleOnPress}
|
||||
text={confirmButtonText}
|
||||
theme={theme}
|
||||
buttonType={submitButtonEnabled ? 'destructive' : 'disabled'}
|
||||
size='lg'
|
||||
iconComponent={buttonIcon}
|
||||
disabled={!submitButtonEnabled}
|
||||
isDestructive={true}
|
||||
showLoader={conversionInProgress}
|
||||
/>
|
||||
{
|
||||
errorMessage &&
|
||||
|
|
|
|||
|
|
@ -1,17 +1,14 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Button} from '@rneui/base';
|
||||
import React, {type MutableRefObject, useCallback, useEffect, useRef} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {defineMessages, useIntl} from 'react-intl';
|
||||
import {Keyboard, Platform, useWindowDimensions, View} from 'react-native';
|
||||
|
||||
import Button from '@components/button';
|
||||
import FloatingTextInput, {type FloatingTextInputRef} from '@components/floating_text_input_label';
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import Loading from '@components/loading';
|
||||
import {useIsTablet} from '@hooks/device';
|
||||
import {t} from '@i18n';
|
||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {typography} from '@utils/typography';
|
||||
import {removeProtocol, stripTrailingSlashes} from '@utils/url';
|
||||
|
|
@ -49,24 +46,23 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
|||
marginTop: 8,
|
||||
...typography('Body', 75, 'Regular'),
|
||||
},
|
||||
connectButton: {
|
||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.08),
|
||||
buttonContainer: {
|
||||
width: '100%',
|
||||
marginTop: 32,
|
||||
marginLeft: 20,
|
||||
marginRight: 20,
|
||||
},
|
||||
loadingContainerStyle: {
|
||||
marginRight: 10,
|
||||
padding: 0,
|
||||
top: -2,
|
||||
},
|
||||
loading: {
|
||||
height: 20,
|
||||
width: 20,
|
||||
},
|
||||
}));
|
||||
|
||||
const messages = defineMessages({
|
||||
save: {
|
||||
id: 'edit_server.save',
|
||||
defaultMessage: 'Save',
|
||||
},
|
||||
saving: {
|
||||
id: 'edit_server.saving',
|
||||
defaultMessage: 'Saving',
|
||||
},
|
||||
});
|
||||
|
||||
const EditServerForm = ({
|
||||
buttonDisabled,
|
||||
connecting,
|
||||
|
|
@ -91,7 +87,7 @@ const EditServerForm = ({
|
|||
keyboardAwareRef.current?.scrollToPosition(0, 0);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
}, [keyboardAwareRef]);
|
||||
|
||||
const onUpdate = useCallback(() => {
|
||||
Keyboard.dismiss();
|
||||
|
|
@ -114,7 +110,7 @@ const EditServerForm = ({
|
|||
keyboardAwareRef.current?.scrollToPosition(0, offsetY);
|
||||
});
|
||||
}
|
||||
}, [dimensions, isTablet]);
|
||||
}, [dimensions, isTablet, keyboardAwareRef]);
|
||||
|
||||
useEffect(() => {
|
||||
if (Platform.OS === 'ios' && isTablet) {
|
||||
|
|
@ -126,25 +122,6 @@ const EditServerForm = ({
|
|||
}
|
||||
}, [onFocus]);
|
||||
|
||||
const buttonType = buttonDisabled ? 'disabled' : 'default';
|
||||
const styleButtonText = buttonTextStyle(theme, 'lg', 'primary', buttonType);
|
||||
const styleButtonBackground = buttonBackgroundStyle(theme, 'lg', 'primary', buttonType);
|
||||
|
||||
let buttonID = t('edit_server.save');
|
||||
let buttonText = 'Save';
|
||||
let buttonIcon;
|
||||
|
||||
if (connecting) {
|
||||
buttonID = t('edit_server.saving');
|
||||
buttonText = 'Saving';
|
||||
buttonIcon = (
|
||||
<Loading
|
||||
containerStyle={styles.loadingContainerStyle}
|
||||
color={theme.buttonColor}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const saveButtonTestId = buttonDisabled ? 'edit_server_form.save.button.disabled' : 'edit_server_form.save.button';
|
||||
|
||||
return (
|
||||
|
|
@ -180,21 +157,17 @@ const EditServerForm = ({
|
|||
values={{url: removeProtocol(stripTrailingSlashes(serverUrl))}}
|
||||
/>
|
||||
}
|
||||
<View style={styles.buttonContainer}>
|
||||
<Button
|
||||
containerStyle={styles.connectButton}
|
||||
buttonStyle={styleButtonBackground}
|
||||
disabledStyle={styleButtonBackground}
|
||||
disabled={buttonDisabled}
|
||||
disabled={buttonDisabled || connecting}
|
||||
onPress={onUpdate}
|
||||
testID={saveButtonTestId}
|
||||
>
|
||||
{buttonIcon}
|
||||
<FormattedText
|
||||
defaultMessage={buttonText}
|
||||
id={buttonID}
|
||||
style={styleButtonText}
|
||||
size='lg'
|
||||
theme={theme}
|
||||
text={formatMessage(connecting ? messages.saving : messages.save)}
|
||||
showLoader={connecting}
|
||||
/>
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Button} from '@rneui/base';
|
||||
import React, {useCallback, useEffect, useRef, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {Keyboard, Platform, Text, useWindowDimensions, View} from 'react-native';
|
||||
|
|
@ -11,6 +10,7 @@ import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-nati
|
|||
import {SafeAreaView} from 'react-native-safe-area-context';
|
||||
|
||||
import {sendPasswordResetEmail} from '@actions/remote/session';
|
||||
import Button from '@components/button';
|
||||
import FloatingTextInput from '@components/floating_text_input_label';
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import {Screens} from '@constants';
|
||||
|
|
@ -18,7 +18,6 @@ import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
|
|||
import {useAvoidKeyboard} from '@hooks/device';
|
||||
import SecurityManager from '@managers/security_manager';
|
||||
import Background from '@screens/background';
|
||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||
import {isEmail} from '@utils/helpers';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {typography} from '@utils/typography';
|
||||
|
|
@ -65,7 +64,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
|||
justifyContent: 'center',
|
||||
paddingHorizontal: 24,
|
||||
},
|
||||
returnButton: {
|
||||
returnButtonContainer: {
|
||||
marginTop: 32,
|
||||
},
|
||||
subheader: {
|
||||
|
|
@ -158,17 +157,15 @@ const ForgotPassword = ({componentId, serverUrl, theme}: Props) => {
|
|||
<Text style={styles.successText}>
|
||||
{email}
|
||||
</Text>
|
||||
<View style={styles.returnButtonContainer}>
|
||||
<Button
|
||||
testID='password_send.return'
|
||||
onPress={onReturn}
|
||||
buttonStyle={[styles.returnButton, buttonBackgroundStyle(theme, 'lg', 'primary', 'default')]}
|
||||
>
|
||||
<FormattedText
|
||||
id='password_send.return'
|
||||
defaultMessage='Return to Log In'
|
||||
style={buttonTextStyle(theme, 'lg', 'primary', 'default')}
|
||||
size='lg'
|
||||
theme={theme}
|
||||
text={formatMessage({id: 'password_send.return', defaultMessage: 'Return to Log In'})}
|
||||
/>
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
|
@ -221,19 +218,16 @@ const ForgotPassword = ({componentId, serverUrl, theme}: Props) => {
|
|||
theme={theme}
|
||||
value={email}
|
||||
/>
|
||||
<View style={styles.returnButtonContainer}>
|
||||
<Button
|
||||
testID='forgot.password.button'
|
||||
buttonStyle={[styles.returnButton, buttonBackgroundStyle(theme, 'lg', 'primary', 'default'), error ? styles.error : undefined]}
|
||||
disabledStyle={[styles.returnButton, buttonBackgroundStyle(theme, 'lg', 'primary', 'disabled'), error ? styles.error : undefined]}
|
||||
disabled={!email}
|
||||
onPress={submitResetPassword}
|
||||
>
|
||||
<FormattedText
|
||||
id='password_send.reset'
|
||||
defaultMessage='Reset my password'
|
||||
style={buttonTextStyle(theme, 'lg', 'primary', email ? 'default' : 'disabled')}
|
||||
size='lg'
|
||||
text={formatMessage({id: 'password_send.reset', defaultMessage: 'Reset my password'})}
|
||||
theme={theme}
|
||||
/>
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</KeyboardAwareScrollView>
|
||||
|
|
|
|||
|
|
@ -256,11 +256,34 @@ exports[`components/categories_list should render channels error 1`] = `
|
|||
There was a problem loading content for this team.
|
||||
</Text>
|
||||
<View
|
||||
style={
|
||||
{
|
||||
"marginTop": 24,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
[
|
||||
{
|
||||
"overflow": "hidden",
|
||||
},
|
||||
{
|
||||
"borderRadius": 2,
|
||||
},
|
||||
undefined,
|
||||
false,
|
||||
]
|
||||
}
|
||||
testID="RNE_BUTTON_WRAPPER"
|
||||
>
|
||||
<View
|
||||
accessibilityRole="button"
|
||||
accessibilityState={
|
||||
{
|
||||
"busy": undefined,
|
||||
"busy": false,
|
||||
"checked": undefined,
|
||||
"disabled": undefined,
|
||||
"disabled": false,
|
||||
"expanded": undefined,
|
||||
"selected": undefined,
|
||||
}
|
||||
|
|
@ -285,34 +308,56 @@ exports[`components/categories_list should render channels error 1`] = `
|
|||
onStartShouldSetResponder={[Function]}
|
||||
style={
|
||||
{
|
||||
"backgroundColor": "#ffffff",
|
||||
"borderRadius": 4,
|
||||
"marginTop": 24,
|
||||
"opacity": 1,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
{
|
||||
"alignItems": "center",
|
||||
"backgroundColor": "#1c58d9",
|
||||
"borderColor": "#2089dc",
|
||||
"borderRadius": 4,
|
||||
"borderWidth": 0,
|
||||
"flexDirection": "row",
|
||||
"justifyContent": "center",
|
||||
"padding": 8,
|
||||
"paddingHorizontal": 24,
|
||||
"paddingVertical": 12,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
<View
|
||||
style={
|
||||
[
|
||||
{
|
||||
"alignItems": "center",
|
||||
"flexDirection": "row",
|
||||
"gap": 7,
|
||||
}
|
||||
}
|
||||
testID="undefined-text-container"
|
||||
>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={
|
||||
{
|
||||
"color": "#ffffff",
|
||||
"fontFamily": "OpenSans-SemiBold",
|
||||
"fontSize": 16,
|
||||
"fontWeight": "600",
|
||||
"lineHeight": 24,
|
||||
},
|
||||
{
|
||||
"color": "#1c58d9",
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
>
|
||||
Retry
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
`;
|
||||
|
||||
|
|
@ -643,11 +688,34 @@ exports[`components/categories_list should render team error 1`] = `
|
|||
There was a problem loading content for this server.
|
||||
</Text>
|
||||
<View
|
||||
style={
|
||||
{
|
||||
"marginTop": 24,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
[
|
||||
{
|
||||
"overflow": "hidden",
|
||||
},
|
||||
{
|
||||
"borderRadius": 2,
|
||||
},
|
||||
undefined,
|
||||
false,
|
||||
]
|
||||
}
|
||||
testID="RNE_BUTTON_WRAPPER"
|
||||
>
|
||||
<View
|
||||
accessibilityRole="button"
|
||||
accessibilityState={
|
||||
{
|
||||
"busy": undefined,
|
||||
"busy": false,
|
||||
"checked": undefined,
|
||||
"disabled": undefined,
|
||||
"disabled": false,
|
||||
"expanded": undefined,
|
||||
"selected": undefined,
|
||||
}
|
||||
|
|
@ -672,33 +740,55 @@ exports[`components/categories_list should render team error 1`] = `
|
|||
onStartShouldSetResponder={[Function]}
|
||||
style={
|
||||
{
|
||||
"backgroundColor": "#ffffff",
|
||||
"borderRadius": 4,
|
||||
"marginTop": 24,
|
||||
"opacity": 1,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
{
|
||||
"alignItems": "center",
|
||||
"backgroundColor": "#1c58d9",
|
||||
"borderColor": "#2089dc",
|
||||
"borderRadius": 4,
|
||||
"borderWidth": 0,
|
||||
"flexDirection": "row",
|
||||
"justifyContent": "center",
|
||||
"padding": 8,
|
||||
"paddingHorizontal": 24,
|
||||
"paddingVertical": 12,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
<View
|
||||
style={
|
||||
[
|
||||
{
|
||||
"alignItems": "center",
|
||||
"flexDirection": "row",
|
||||
"gap": 7,
|
||||
}
|
||||
}
|
||||
testID="undefined-text-container"
|
||||
>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={
|
||||
{
|
||||
"color": "#ffffff",
|
||||
"fontFamily": "OpenSans-SemiBold",
|
||||
"fontSize": 16,
|
||||
"fontWeight": "600",
|
||||
"lineHeight": 24,
|
||||
},
|
||||
{
|
||||
"color": "#1c58d9",
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
>
|
||||
Retry
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import React, {useMemo} from 'react';
|
||||
import React from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {View} from 'react-native';
|
||||
|
||||
import {showUnreadChannelsOnly} from '@actions/local/channel';
|
||||
import Button from '@components/button';
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import TouchableWithFeedback from '@components/touchable_with_feedback';
|
||||
import {useServerUrl} from '@context/server';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {typography} from '@utils/typography';
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ type Props = {
|
|||
}
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||
button: {
|
||||
buttonContainer: {
|
||||
marginTop: 24,
|
||||
},
|
||||
container: {
|
||||
|
|
@ -45,13 +45,11 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
|||
}));
|
||||
|
||||
function EmptyUnreads({onlyUnreads}: Props) {
|
||||
const intl = useIntl();
|
||||
const theme = useTheme();
|
||||
const serverUrl = useServerUrl();
|
||||
const styles = getStyleSheet(theme);
|
||||
|
||||
const buttonStyle = useMemo(() => [buttonBackgroundStyle(theme, 'lg', 'tertiary', 'inverted'), styles.button],
|
||||
[theme]);
|
||||
|
||||
const onPress = () => {
|
||||
showUnreadChannelsOnly(serverUrl, !onlyUnreads);
|
||||
};
|
||||
|
|
@ -71,17 +69,16 @@ function EmptyUnreads({onlyUnreads}: Props) {
|
|||
style={styles.paragraph}
|
||||
testID='unreads.empty.paragraph'
|
||||
/>
|
||||
<TouchableWithFeedback
|
||||
style={buttonStyle}
|
||||
<View style={styles.buttonContainer}>
|
||||
<Button
|
||||
text={intl.formatMessage({id: 'unreads.empty.show_all', defaultMessage: 'Show all'})}
|
||||
theme={theme}
|
||||
size='lg'
|
||||
onPress={onPress}
|
||||
type={'opacity'}
|
||||
>
|
||||
<FormattedText
|
||||
id='unreads.empty.show_all'
|
||||
defaultMessage='Show all'
|
||||
style={buttonTextStyle(theme, 'lg', 'tertiary', 'inverted')}
|
||||
emphasis='tertiary'
|
||||
isInverted={true}
|
||||
/>
|
||||
</TouchableWithFeedback>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,15 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Button} from '@rneui/base';
|
||||
import React, {useCallback, useMemo} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {defineMessages, useIntl} from 'react-intl';
|
||||
import {View, Text, ScrollView} from 'react-native';
|
||||
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import Button from '@components/button';
|
||||
import AlertSvg from '@components/illustrations/alert';
|
||||
import ErrorSvg from '@components/illustrations/error';
|
||||
import SuccessSvg from '@components/illustrations/success';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {t} from '@i18n';
|
||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||
import {makeStyleSheetFromTheme, changeOpacity} from '@utils/theme';
|
||||
import {typography} from '@utils/typography';
|
||||
|
||||
|
|
@ -77,17 +73,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
|||
flexGrow: 1,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
summaryButtonTextContainer: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
height: 24,
|
||||
},
|
||||
summaryButtonIcon: {
|
||||
marginRight: 7,
|
||||
color: theme.buttonColor,
|
||||
|
||||
gap: 8,
|
||||
},
|
||||
summaryButtonContainerStyle: {flexGrow: 1},
|
||||
};
|
||||
|
|
@ -109,6 +95,21 @@ type SummaryProps = {
|
|||
onBack: () => void;
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
done: {
|
||||
id: 'invite.summary.done',
|
||||
defaultMessage: 'Done',
|
||||
},
|
||||
tryAgain: {
|
||||
id: 'invite.summary.try_again',
|
||||
defaultMessage: 'Try again',
|
||||
},
|
||||
back: {
|
||||
id: 'invite.summary.back',
|
||||
defaultMessage: 'Go back',
|
||||
},
|
||||
});
|
||||
|
||||
export default function Summary({
|
||||
result,
|
||||
selectedIds,
|
||||
|
|
@ -118,7 +119,7 @@ export default function Summary({
|
|||
onRetry,
|
||||
onBack,
|
||||
}: SummaryProps) {
|
||||
const {formatMessage, locale} = useIntl();
|
||||
const {formatMessage} = useIntl();
|
||||
const theme = useTheme();
|
||||
const styles = getStyleSheet(theme);
|
||||
|
||||
|
|
@ -183,64 +184,41 @@ export default function Summary({
|
|||
let onPress;
|
||||
let iconName = '';
|
||||
let text;
|
||||
let styleButtonText = buttonTextStyle(theme, 'lg', 'primary');
|
||||
let styleButtonBackground = buttonBackgroundStyle(theme, 'lg', 'primary');
|
||||
const styleButtonIcon = [];
|
||||
styleButtonIcon.push(styles.summaryButtonIcon);
|
||||
let emphasis: ButtonEmphasis = 'primary';
|
||||
|
||||
switch (type) {
|
||||
case SummaryButtonType.BACK:
|
||||
onPress = onBack;
|
||||
iconName = 'chevron-left';
|
||||
text = {
|
||||
id: t('invite.summary.back'),
|
||||
defaultMessage: 'Go back',
|
||||
};
|
||||
styleButtonText = buttonTextStyle(theme, 'lg', 'tertiary');
|
||||
styleButtonBackground = [buttonBackgroundStyle(theme, 'lg', 'tertiary'), {marginRight: 8}];
|
||||
styleButtonIcon.push({color: theme.buttonBg});
|
||||
text = messages.back;
|
||||
emphasis = 'tertiary';
|
||||
break;
|
||||
case SummaryButtonType.RETRY:
|
||||
onPress = onRetry;
|
||||
iconName = 'refresh';
|
||||
text = {
|
||||
id: t('invite.summary.try_again'),
|
||||
defaultMessage: 'Try again',
|
||||
};
|
||||
text = messages.tryAgain;
|
||||
break;
|
||||
case SummaryButtonType.DONE:
|
||||
default:
|
||||
onPress = onClose;
|
||||
text = {
|
||||
id: t('invite.summary.done'),
|
||||
defaultMessage: 'Done',
|
||||
};
|
||||
text = messages.done;
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.summaryButtonContainerStyle}>
|
||||
<Button
|
||||
containerStyle={styles.summaryButtonContainerStyle}
|
||||
buttonStyle={styleButtonBackground}
|
||||
onPress={onPress}
|
||||
testID={`invite.summary_button.${SummaryButtonType.RETRY}`}
|
||||
>
|
||||
<View style={styles.summaryButtonTextContainer}>
|
||||
{iconName && (
|
||||
<CompassIcon
|
||||
name={iconName}
|
||||
size={24}
|
||||
style={styleButtonIcon}
|
||||
/>
|
||||
)}
|
||||
<FormattedText
|
||||
{...text}
|
||||
style={styleButtonText}
|
||||
text={formatMessage(text)}
|
||||
iconName={iconName}
|
||||
emphasis={emphasis}
|
||||
size='lg'
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
</Button>
|
||||
);
|
||||
}, [theme, locale, onClose, onRetry, onBack]);
|
||||
}, [styles.summaryButtonContainerStyle, formatMessage, theme, onBack, onRetry, onClose]);
|
||||
|
||||
return (
|
||||
<View
|
||||
|
|
|
|||
|
|
@ -2,21 +2,19 @@
|
|||
// See LICENSE.txt for license information.
|
||||
|
||||
import {useManagedConfig} from '@mattermost/react-native-emm';
|
||||
import {Button} from '@rneui/base';
|
||||
import {Button as RNEButton} from '@rneui/base';
|
||||
import React, {useCallback, useEffect, useMemo, useRef, useState, type RefObject} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {defineMessages, useIntl} from 'react-intl';
|
||||
import {Keyboard, TextInput, TouchableOpacity, View} from 'react-native';
|
||||
|
||||
import {login} from '@actions/remote/session';
|
||||
import Button from '@components/button';
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import FloatingTextInput from '@components/floating_text_input_label';
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import Loading from '@components/loading';
|
||||
import {FORGOT_PASSWORD, MFA} from '@constants/screens';
|
||||
import {useAvoidKeyboard} from '@hooks/device';
|
||||
import {t} from '@i18n';
|
||||
import {goToScreen, loginAnimationOptions, resetToHome} from '@screens/navigation';
|
||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||
import {getFullErrorMessage, getServerError, isErrorWithMessage, isServerError} from '@utils/errors';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
|
@ -67,12 +65,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
|||
fontSize: 14,
|
||||
fontFamily: 'OpenSans-SemiBold',
|
||||
},
|
||||
loadingContainerStyle: {
|
||||
marginRight: 10,
|
||||
padding: 0,
|
||||
top: -2,
|
||||
},
|
||||
loginButton: {
|
||||
loginButtonContainer: {
|
||||
marginTop: 25,
|
||||
},
|
||||
endAdornment: {
|
||||
|
|
@ -80,6 +73,17 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
|||
},
|
||||
}));
|
||||
|
||||
const messages = defineMessages({
|
||||
signIn: {
|
||||
id: 'login.signIn',
|
||||
defaultMessage: 'Log In',
|
||||
},
|
||||
signingIn: {
|
||||
id: 'login.signingIn',
|
||||
defaultMessage: 'Logging In',
|
||||
},
|
||||
});
|
||||
|
||||
const LoginForm = ({config, extra, keyboardAwareRef, serverDisplayName, launchError, launchType, license, serverUrl, theme}: LoginProps) => {
|
||||
const styles = getStyleSheet(theme);
|
||||
const loginRef = useRef<TextInput>(null);
|
||||
|
|
@ -256,44 +260,20 @@ const LoginForm = ({config, extra, keyboardAwareRef, serverDisplayName, launchEr
|
|||
}, [loginId, password]);
|
||||
|
||||
const renderProceedButton = useMemo(() => {
|
||||
const buttonType = buttonDisabled ? 'disabled' : 'default';
|
||||
const styleButtonText = buttonTextStyle(theme, 'lg', 'primary', buttonType);
|
||||
const styleButtonBackground = buttonBackgroundStyle(theme, 'lg', 'primary', buttonType);
|
||||
|
||||
let buttonID = t('login.signIn');
|
||||
let buttonText = 'Log In';
|
||||
let buttonIcon;
|
||||
|
||||
if (isLoading) {
|
||||
buttonID = t('login.signingIn');
|
||||
buttonText = 'Logging In';
|
||||
buttonIcon = (
|
||||
<Loading
|
||||
containerStyle={styles.loadingContainerStyle}
|
||||
color={theme.buttonColor}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const signinButtonTestId = buttonDisabled ? 'login_form.signin.button.disabled' : 'login_form.signin.button';
|
||||
|
||||
return (
|
||||
<View style={styles.loginButtonContainer}>
|
||||
<Button
|
||||
disabled={buttonDisabled}
|
||||
onPress={onLogin}
|
||||
buttonStyle={[styles.loginButton, styleButtonBackground]}
|
||||
disabledStyle={[styles.loginButton, styleButtonBackground]}
|
||||
testID={signinButtonTestId}
|
||||
>
|
||||
{buttonIcon}
|
||||
<FormattedText
|
||||
id={buttonID}
|
||||
defaultMessage={buttonText}
|
||||
style={styleButtonText}
|
||||
size='lg'
|
||||
testID={buttonDisabled ? 'login_form.signin.button.disabled' : 'login_form.signin.button'}
|
||||
text={intl.formatMessage(isLoading ? messages.signingIn : messages.signIn)}
|
||||
showLoader={isLoading}
|
||||
theme={theme}
|
||||
/>
|
||||
</Button>
|
||||
</View>
|
||||
);
|
||||
}, [buttonDisabled, loginId, password, isLoading, theme]);
|
||||
}, [styles.loginButtonContainer, buttonDisabled, onLogin, intl, isLoading, theme]);
|
||||
|
||||
const endAdornment = (
|
||||
<TouchableOpacity
|
||||
|
|
@ -356,7 +336,7 @@ const LoginForm = ({config, extra, keyboardAwareRef, serverDisplayName, launchEr
|
|||
/>
|
||||
|
||||
{(emailEnabled || usernameEnabled) && config.PasswordEnableForgotLink !== 'false' && (
|
||||
<Button
|
||||
<RNEButton
|
||||
onPress={onPressForgotPassword}
|
||||
buttonStyle={[styles.forgotPasswordBtn, error ? styles.forgotPasswordError : undefined]}
|
||||
testID='login_form.forgot_password.button'
|
||||
|
|
@ -366,7 +346,7 @@ const LoginForm = ({config, extra, keyboardAwareRef, serverDisplayName, launchEr
|
|||
defaultMessage='Forgot your password?'
|
||||
style={styles.forgotPasswordTxt}
|
||||
/>
|
||||
</Button>
|
||||
</RNEButton>
|
||||
)}
|
||||
{renderProceedButton}
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,12 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Button} from '@rneui/base';
|
||||
import React from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {Image, type ImageSourcePropType, Text, View} from 'react-native';
|
||||
import {Image, type ImageSourcePropType, StyleSheet, View} from 'react-native';
|
||||
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import Button from '@components/button';
|
||||
import {Sso} from '@constants';
|
||||
import {buttonBackgroundStyle} from '@utils/buttonStyles';
|
||||
import {makeStyleSheetFromTheme, changeOpacity} from '@utils/theme';
|
||||
|
||||
type SsoInfo = {
|
||||
text: string;
|
||||
|
|
@ -26,8 +23,6 @@ type Props = {
|
|||
|
||||
const SsoOptions = ({goToSso, ssoOnly, ssoOptions, theme}: Props) => {
|
||||
const {formatMessage} = useIntl();
|
||||
const styles = getStyleSheet(theme);
|
||||
const styleButtonBackground = buttonBackgroundStyle(theme, 'lg', 'primary');
|
||||
|
||||
const getSsoButtonOptions = ((ssoType: string): SsoInfo => {
|
||||
const sso: SsoInfo = {} as SsoInfo;
|
||||
|
|
@ -63,12 +58,8 @@ const SsoOptions = ({goToSso, ssoOnly, ssoOptions, theme}: Props) => {
|
|||
(ssoType: string) => ssoOptions[ssoType].enabled,
|
||||
);
|
||||
|
||||
let styleViewContainer;
|
||||
let styleButtonContainer;
|
||||
if (enabledSSOs.length === 2 && !ssoOnly) {
|
||||
styleViewContainer = styles.containerAsRow;
|
||||
styleButtonContainer = styles.buttonContainer;
|
||||
}
|
||||
const styleViewContainer = enabledSSOs.length === 2 && !ssoOnly ? styles.containerAsRow : undefined;
|
||||
const styleButtonWrapper = enabledSSOs.length === 2 && !ssoOnly ? styles.buttonWrapper : undefined;
|
||||
|
||||
const componentArray = [];
|
||||
for (const ssoType of enabledSSOs) {
|
||||
|
|
@ -78,38 +69,24 @@ const SsoOptions = ({goToSso, ssoOnly, ssoOptions, theme}: Props) => {
|
|||
};
|
||||
|
||||
componentArray.push(
|
||||
<View style={styleButtonWrapper}>
|
||||
<Button
|
||||
key={ssoType}
|
||||
onPress={handlePress}
|
||||
buttonStyle={[styleButtonBackground, styles.button]}
|
||||
containerStyle={styleButtonContainer}
|
||||
>
|
||||
{imageSrc && (
|
||||
size='lg'
|
||||
theme={theme}
|
||||
iconName={compassIcon}
|
||||
emphasis='secondary'
|
||||
iconComponent={imageSrc ? (
|
||||
<Image
|
||||
key={'image' + ssoType}
|
||||
source={imageSrc}
|
||||
style={styles.logoStyle}
|
||||
/>
|
||||
)}
|
||||
{compassIcon &&
|
||||
<CompassIcon
|
||||
name={compassIcon}
|
||||
size={16}
|
||||
color={theme.centerChannelColor}
|
||||
) : undefined}
|
||||
text={text}
|
||||
/>
|
||||
}
|
||||
<View
|
||||
style={styles.buttonTextContainer}
|
||||
>
|
||||
<Text
|
||||
key={ssoType}
|
||||
style={styles.buttonText}
|
||||
testID={text}
|
||||
>
|
||||
{text}
|
||||
</Text>
|
||||
</View>
|
||||
</Button>,
|
||||
</View>,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -120,41 +97,23 @@ const SsoOptions = ({goToSso, ssoOnly, ssoOptions, theme}: Props) => {
|
|||
);
|
||||
};
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
marginVertical: 24,
|
||||
gap: 8,
|
||||
},
|
||||
containerAsRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
buttonContainer: {
|
||||
width: '48%',
|
||||
marginRight: 8,
|
||||
},
|
||||
button: {
|
||||
marginVertical: 4,
|
||||
backgroundColor: 'transparent',
|
||||
borderWidth: 1,
|
||||
borderColor: changeOpacity(theme.centerChannelColor, 0.16),
|
||||
},
|
||||
buttonTextContainer: {
|
||||
color: theme.centerChannelColor,
|
||||
flexDirection: 'row',
|
||||
marginLeft: 9,
|
||||
},
|
||||
buttonText: {
|
||||
color: theme.centerChannelColor,
|
||||
fontFamily: 'OpenSans-SemiBold',
|
||||
fontSize: 16,
|
||||
lineHeight: 18,
|
||||
top: 2,
|
||||
buttonWrapper: {
|
||||
flex: 1,
|
||||
},
|
||||
logoStyle: {
|
||||
height: 18,
|
||||
marginRight: 5,
|
||||
width: 18,
|
||||
},
|
||||
}));
|
||||
});
|
||||
|
||||
export default SsoOptions;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Button} from '@rneui/base';
|
||||
import React, {useCallback, useEffect, useRef, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {Keyboard, Platform, useWindowDimensions, View} from 'react-native';
|
||||
|
|
@ -11,18 +10,16 @@ import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-nati
|
|||
import {SafeAreaView} from 'react-native-safe-area-context';
|
||||
|
||||
import {login} from '@actions/remote/session';
|
||||
import Button from '@components/button';
|
||||
import FloatingTextInput from '@components/floating_text_input_label';
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import Loading from '@components/loading';
|
||||
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
|
||||
import {useAvoidKeyboard} from '@hooks/device';
|
||||
import {t} from '@i18n';
|
||||
import {usePreventDoubleTap} from '@hooks/utils';
|
||||
import SecurityManager from '@managers/security_manager';
|
||||
import Background from '@screens/background';
|
||||
import {popTopScreen} from '@screens/navigation';
|
||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||
import {getErrorMessage} from '@utils/errors';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {typography} from '@utils/typography';
|
||||
|
||||
|
|
@ -52,9 +49,6 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
|||
justifyContent: 'center',
|
||||
marginTop: Platform.select({android: 56}),
|
||||
},
|
||||
error: {
|
||||
marginTop: 64,
|
||||
},
|
||||
flex: {
|
||||
flex: 1,
|
||||
},
|
||||
|
|
@ -72,16 +66,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
|||
paddingHorizontal: 24,
|
||||
height: '100%',
|
||||
},
|
||||
loading: {
|
||||
height: 20,
|
||||
width: 20,
|
||||
},
|
||||
loadingContainerStyle: {
|
||||
marginRight: 10,
|
||||
padding: 0,
|
||||
top: -2,
|
||||
},
|
||||
proceedButton: {
|
||||
proceedButtonContainer: {
|
||||
marginTop: 32,
|
||||
},
|
||||
shield: {
|
||||
|
|
@ -114,12 +99,12 @@ const MFA = ({componentId, config, goToHome, license, loginId, password, serverD
|
|||
setError('');
|
||||
}, []);
|
||||
|
||||
const submit = useCallback(preventDoubleTap(async () => {
|
||||
const submit = usePreventDoubleTap(useCallback(async () => {
|
||||
Keyboard.dismiss();
|
||||
if (!token) {
|
||||
setError(
|
||||
formatMessage({
|
||||
id: t('login_mfa.tokenReq'),
|
||||
id: 'login_mfa.tokenReq',
|
||||
defaultMessage: 'Please enter an MFA token',
|
||||
}),
|
||||
);
|
||||
|
|
@ -133,7 +118,7 @@ const MFA = ({componentId, config, goToHome, license, loginId, password, serverD
|
|||
return;
|
||||
}
|
||||
goToHome(result.error);
|
||||
}), [token]);
|
||||
}, [config, formatMessage, goToHome, intl, license, loginId, password, serverDisplayName, serverUrl, token]));
|
||||
|
||||
const transform = useAnimatedStyle(() => {
|
||||
const duration = Platform.OS === 'android' ? 250 : 350;
|
||||
|
|
@ -224,25 +209,18 @@ const MFA = ({componentId, config, goToHome, license, loginId, password, serverD
|
|||
theme={theme}
|
||||
value={token}
|
||||
/>
|
||||
<View style={styles.proceedButtonContainer}>
|
||||
<Button
|
||||
testID='login_mfa.submit'
|
||||
buttonStyle={[styles.proceedButton, buttonBackgroundStyle(theme, 'lg', 'primary', 'default'), error ? styles.error : undefined]}
|
||||
disabledStyle={[styles.proceedButton, buttonBackgroundStyle(theme, 'lg', 'primary', 'disabled'), error ? styles.error : undefined]}
|
||||
size='lg'
|
||||
disabled={!token}
|
||||
onPress={submit}
|
||||
>
|
||||
{isLoading &&
|
||||
<Loading
|
||||
containerStyle={styles.loadingContainerStyle}
|
||||
color={theme.buttonColor}
|
||||
theme={theme}
|
||||
showLoader={isLoading}
|
||||
text={formatMessage({id: 'mobile.components.select_server_view.proceed', defaultMessage: 'Proceed'})}
|
||||
isDestructive={Boolean(error)}
|
||||
/>
|
||||
}
|
||||
<FormattedText
|
||||
id='mobile.components.select_server_view.proceed'
|
||||
defaultMessage='Proceed'
|
||||
style={buttonTextStyle(theme, 'lg', 'primary', token ? 'default' : 'disabled')}
|
||||
/>
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</KeyboardAwareScrollView>
|
||||
|
|
|
|||
|
|
@ -2,14 +2,13 @@
|
|||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {Pressable, useWindowDimensions, View} from 'react-native';
|
||||
import {Pressable, StyleSheet, useWindowDimensions, View} from 'react-native';
|
||||
import Animated, {Extrapolate, interpolate, useAnimatedStyle} from 'react-native-reanimated';
|
||||
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import {ONBOARDING_CONTENT_MAX_WIDTH} from '@screens/onboarding/slide';
|
||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
type Props = {
|
||||
theme: Theme;
|
||||
|
|
@ -19,24 +18,20 @@ type Props = {
|
|||
scrollX: Animated.SharedValue<number>;
|
||||
};
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
marginTop: 5,
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
rowIcon: {
|
||||
color: theme.buttonColor,
|
||||
fontSize: 12,
|
||||
marginLeft: 5,
|
||||
marginTop: 4.5,
|
||||
},
|
||||
nextButtonText: {
|
||||
flexDirection: 'row',
|
||||
position: 'absolute',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
width: 120,
|
||||
gap: 5,
|
||||
},
|
||||
footerButtonsContainer: {
|
||||
flexDirection: 'column',
|
||||
|
|
@ -46,7 +41,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
|||
width: '100%',
|
||||
alignItems: 'center',
|
||||
},
|
||||
}));
|
||||
});
|
||||
|
||||
const AnimatedButton = Animated.createAnimatedComponent(Pressable);
|
||||
const BUTTON_SIZE = 120;
|
||||
|
|
@ -60,7 +55,6 @@ const FooterButtons = ({
|
|||
}: Props) => {
|
||||
const {width} = useWindowDimensions();
|
||||
const buttonWidth = Math.min(width * 0.8, ONBOARDING_CONTENT_MAX_WIDTH);
|
||||
const styles = getStyleSheet(theme);
|
||||
|
||||
// keep in mind penultimate and ultimate slides to run buttons text/opacity/size animations
|
||||
const penultimateSlide = lastSlideIndex - 1;
|
||||
|
|
@ -114,6 +108,8 @@ const FooterButtons = ({
|
|||
return {opacity: interpolatedScale};
|
||||
});
|
||||
|
||||
const textStyles = StyleSheet.flatten(buttonTextStyle(theme, 'lg', 'primary', 'default'));
|
||||
|
||||
const nextButtonText = (
|
||||
<Animated.View style={[styles.nextButtonText, opacityNextTextStyle]}>
|
||||
<FormattedText
|
||||
|
|
@ -123,7 +119,8 @@ const FooterButtons = ({
|
|||
/>
|
||||
<CompassIcon
|
||||
name='arrow-forward-ios'
|
||||
style={styles.rowIcon}
|
||||
size={12}
|
||||
color={textStyles.color}
|
||||
/>
|
||||
</Animated.View>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useCallback, useEffect, useMemo, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {Alert, Text, TouchableOpacity, View} from 'react-native';
|
||||
import Animated from 'react-native-reanimated';
|
||||
import {type Edge, SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context';
|
||||
|
|
@ -10,6 +11,7 @@ import {getPosts} from '@actions/local/post';
|
|||
import {fetchChannelById, joinChannel, switchToChannelById} from '@actions/remote/channel';
|
||||
import {fetchPostById, fetchPostsAround, fetchPostThread} from '@actions/remote/post';
|
||||
import {addCurrentUserToTeam, fetchTeamByName, removeCurrentUserFromTeam} from '@actions/remote/team';
|
||||
import Button from '@components/button';
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import Loading from '@components/loading';
|
||||
|
|
@ -21,12 +23,11 @@ import {useTheme} from '@context/theme';
|
|||
import DatabaseManager from '@database/manager';
|
||||
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
|
||||
import {useIsTablet} from '@hooks/device';
|
||||
import {usePreventDoubleTap} from '@hooks/utils';
|
||||
import SecurityManager from '@managers/security_manager';
|
||||
import {getChannelById, getMyChannel} from '@queries/servers/channel';
|
||||
import {dismissModal} from '@screens/navigation';
|
||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||
import {closePermalink} from '@utils/permalink';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {secureGetFromRecord} from '@utils/types';
|
||||
import {typography} from '@utils/typography';
|
||||
|
|
@ -105,11 +106,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
|||
alignItems: 'center',
|
||||
},
|
||||
footer: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'row',
|
||||
padding: 20,
|
||||
width: '100%',
|
||||
borderBottomLeftRadius: 12,
|
||||
borderBottomRightRadius: 12,
|
||||
borderTopWidth: 1,
|
||||
|
|
@ -139,6 +136,7 @@ function Permalink({
|
|||
isTeamMember,
|
||||
currentTeamId,
|
||||
}: Props) {
|
||||
const intl = useIntl();
|
||||
const [posts, setPosts] = useState<PostModel[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const theme = useTheme();
|
||||
|
|
@ -273,17 +271,17 @@ function Permalink({
|
|||
}
|
||||
dismissModal({componentId: Screens.PERMALINK});
|
||||
closePermalink();
|
||||
}, [error]);
|
||||
}, [error?.joinedTeam, error?.teamId, serverUrl]);
|
||||
|
||||
useAndroidHardwareBackHandler(Screens.PERMALINK, handleClose);
|
||||
|
||||
const handlePress = useCallback(preventDoubleTap(() => {
|
||||
const handlePress = usePreventDoubleTap(useCallback(() => {
|
||||
if (channel) {
|
||||
switchToChannelById(serverUrl, channel.id, channel.teamId);
|
||||
}
|
||||
}), [channel?.id, channel?.teamId]);
|
||||
}, [channel, serverUrl]));
|
||||
|
||||
const handleJoin = useCallback(preventDoubleTap(async () => {
|
||||
const handleJoin = usePreventDoubleTap(useCallback(async () => {
|
||||
setLoading(true);
|
||||
setError(undefined);
|
||||
if (error?.teamId && error.channelId) {
|
||||
|
|
@ -296,7 +294,7 @@ function Permalink({
|
|||
}
|
||||
setChannelId(error.channelId);
|
||||
}
|
||||
}), [error, serverUrl]);
|
||||
}, [error, serverUrl]));
|
||||
|
||||
let content;
|
||||
if (loading) {
|
||||
|
|
@ -334,18 +332,13 @@ function Permalink({
|
|||
/>
|
||||
</View>
|
||||
<View style={style.footer}>
|
||||
<TouchableOpacity
|
||||
style={[buttonBackgroundStyle(theme, 'lg', 'primary'), {width: '100%'}]}
|
||||
<Button
|
||||
size='lg'
|
||||
text={intl.formatMessage({id: 'mobile.search.jump', defaultMessage: 'Jump to recent messages'})}
|
||||
theme={theme}
|
||||
onPress={handlePress}
|
||||
testID='permalink.jump_to_recent_messages.button'
|
||||
>
|
||||
<FormattedText
|
||||
testID='permalink.search.jump'
|
||||
id='mobile.search.jump'
|
||||
defaultMessage='Jump to recent messages'
|
||||
style={buttonTextStyle(theme, 'lg', 'primary')}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</ExtraKeyboardProvider>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,16 +2,15 @@
|
|||
// See LICENSE.txt for license information.
|
||||
import React from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {Text, TouchableOpacity, View} from 'react-native';
|
||||
import {Text, View} from 'react-native';
|
||||
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import Button from '@components/button';
|
||||
import JoinPrivateChannel from '@components/illustrations/join_private_channel';
|
||||
import JoinPublicChannel from '@components/illustrations/join_public_channel';
|
||||
import MessageNotViewable from '@components/illustrations/message_not_viewable';
|
||||
import Markdown from '@components/markdown';
|
||||
import {Screens} from '@constants';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||
import {getMarkdownBlockStyles, getMarkdownTextStyles} from '@utils/markdown';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {typography} from '@utils/typography';
|
||||
|
|
@ -49,6 +48,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
|||
borderTopWidth: 1,
|
||||
borderTopColor: changeOpacity(theme.centerChannelColor, 0.16),
|
||||
padding: 20,
|
||||
gap: 8,
|
||||
},
|
||||
|
||||
};
|
||||
|
|
@ -63,9 +63,6 @@ function PermalinkError({
|
|||
const style = getStyleSheet(theme);
|
||||
const intl = useIntl();
|
||||
|
||||
const buttonStylePrimary = buttonBackgroundStyle(theme, 'lg', 'primary');
|
||||
const buttonTextStylePrimary = buttonTextStyle(theme, 'lg', 'primary');
|
||||
|
||||
if (error.notExist || error.unreachable) {
|
||||
const title = intl.formatMessage({id: 'permalink.error.access.title', defaultMessage: 'Message not viewable'});
|
||||
const text = intl.formatMessage({id: 'permalink.error.access.text', defaultMessage: 'The message you are trying to view is in a channel you don’t have access to or has been deleted.'});
|
||||
|
|
@ -77,25 +74,17 @@ function PermalinkError({
|
|||
<Text style={style.errorText}>{text}</Text>
|
||||
</View>
|
||||
<View style={style.errorButtonContainer}>
|
||||
<TouchableOpacity
|
||||
style={buttonStylePrimary}
|
||||
<Button
|
||||
size='lg'
|
||||
text={intl.formatMessage({id: 'permalink.error.okay', defaultMessage: 'Okay'})}
|
||||
theme={theme}
|
||||
onPress={handleClose}
|
||||
>
|
||||
<FormattedText
|
||||
testID='permalink.error.okay'
|
||||
id='permalink.error.okay'
|
||||
defaultMessage='Okay'
|
||||
style={buttonTextStylePrimary}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const buttonStyleTertiary = buttonBackgroundStyle(theme, 'lg', 'tertiary');
|
||||
const buttonTextStyleTertiary = buttonTextStyle(theme, 'lg', 'tertiary');
|
||||
|
||||
const isPrivate = error.privateChannel || error.privateTeam;
|
||||
let image;
|
||||
let title;
|
||||
|
|
@ -143,23 +132,19 @@ function PermalinkError({
|
|||
/>
|
||||
</View>
|
||||
<View style={style.errorButtonContainer}>
|
||||
<TouchableOpacity
|
||||
style={buttonStylePrimary}
|
||||
<Button
|
||||
size='lg'
|
||||
text={button}
|
||||
theme={theme}
|
||||
onPress={handleJoin}
|
||||
>
|
||||
<Text style={buttonTextStylePrimary}>{button}</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[buttonStyleTertiary, {marginTop: 8}]}
|
||||
onPress={handleClose}
|
||||
>
|
||||
<FormattedText
|
||||
testID='permalink.error.cancel'
|
||||
id='permalink.error.cancel'
|
||||
defaultMessage='Cancel'
|
||||
style={buttonTextStyleTertiary}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<Button
|
||||
size='lg'
|
||||
emphasis='tertiary'
|
||||
onPress={handleClose}
|
||||
text={intl.formatMessage({id: 'permalink.error.cancel', defaultMessage: 'Cancel'})}
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -3,11 +3,10 @@
|
|||
|
||||
import React from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {StyleSheet, Text, View} from 'react-native';
|
||||
import {Text, View} from 'react-native';
|
||||
|
||||
import Empty from '@components/illustrations/no_team';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {typography} from '@utils/typography';
|
||||
|
||||
|
|
@ -40,21 +39,6 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
|||
marginTop: 12,
|
||||
...typography('Body', 200, 'Regular'),
|
||||
},
|
||||
buttonStyle: {
|
||||
...StyleSheet.flatten(buttonBackgroundStyle(theme, 'lg', 'primary', 'default')),
|
||||
flexDirection: 'row',
|
||||
marginTop: 24,
|
||||
},
|
||||
buttonText: {
|
||||
...StyleSheet.flatten(buttonTextStyle(theme, 'lg', 'primary', 'default')),
|
||||
marginLeft: 8,
|
||||
},
|
||||
plusIcon: {
|
||||
color: theme.sidebarText,
|
||||
fontSize: 24,
|
||||
lineHeight: 22,
|
||||
},
|
||||
|
||||
}));
|
||||
|
||||
const NoTeams = () => {
|
||||
|
|
@ -73,7 +57,7 @@ const NoTeams = () => {
|
|||
<Text style={styles.description}>
|
||||
{intl.formatMessage({id: 'select_team.no_team.description', defaultMessage: 'To join a team, ask a team admin for an invite, or create your own team. You may also want to check your email inbox for an invitation.'})}
|
||||
</Text>
|
||||
{/* {canCreateTeams && // TODO https://mattermost.atlassian.net/browse/MM-43622
|
||||
{/* {canCreateTeams && // TODO https://mattermost.atlassian.net/browse/MM-43622 (Use Button component instead of touchable)
|
||||
<TouchableWithFeedback
|
||||
style={styles.buttonStyle}
|
||||
type={'opacity'}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,14 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Button} from '@rneui/base';
|
||||
import React, {type RefObject, useCallback, useRef} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {defineMessages, useIntl} from 'react-intl';
|
||||
import {Keyboard, View} from 'react-native';
|
||||
|
||||
import Button from '@components/button';
|
||||
import FloatingTextInput, {type FloatingTextInputRef} from '@components/floating_text_input_label';
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import Loading from '@components/loading';
|
||||
import {useAvoidKeyboard} from '@hooks/device';
|
||||
import {t} from '@i18n';
|
||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {typography} from '@utils/typography';
|
||||
|
||||
|
|
@ -52,22 +49,25 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
|||
marginTop: 8,
|
||||
...typography('Body', 75, 'Regular'),
|
||||
},
|
||||
connectButton: {
|
||||
connectButtonContainer: {
|
||||
width: '100%',
|
||||
marginTop: 32,
|
||||
marginLeft: 20,
|
||||
marginRight: 20,
|
||||
},
|
||||
connectingIndicator: {
|
||||
marginRight: 10,
|
||||
},
|
||||
loadingContainerStyle: {
|
||||
marginRight: 10,
|
||||
padding: 0,
|
||||
top: -2,
|
||||
},
|
||||
}));
|
||||
|
||||
const messages = defineMessages({
|
||||
connect: {
|
||||
id: 'mobile.components.select_server_view.connect',
|
||||
defaultMessage: 'Connect',
|
||||
},
|
||||
connecting: {
|
||||
id: 'mobile.components.select_server_view.connecting',
|
||||
defaultMessage: 'Connecting',
|
||||
},
|
||||
});
|
||||
|
||||
const ServerForm = ({
|
||||
autoFocus = false,
|
||||
buttonDisabled,
|
||||
|
|
@ -99,25 +99,6 @@ const ServerForm = ({
|
|||
displayNameRef.current?.focus();
|
||||
}, []);
|
||||
|
||||
const buttonType = buttonDisabled ? 'disabled' : 'default';
|
||||
const styleButtonText = buttonTextStyle(theme, 'lg', 'primary', buttonType);
|
||||
const styleButtonBackground = buttonBackgroundStyle(theme, 'lg', 'primary', buttonType);
|
||||
|
||||
let buttonID = t('mobile.components.select_server_view.connect');
|
||||
let buttonText = 'Connect';
|
||||
let buttonIcon;
|
||||
|
||||
if (connecting) {
|
||||
buttonID = t('mobile.components.select_server_view.connecting');
|
||||
buttonText = 'Connecting';
|
||||
buttonIcon = (
|
||||
<Loading
|
||||
containerStyle={styles.loadingContainerStyle}
|
||||
color={theme.buttonColor}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const connectButtonTestId = buttonDisabled ? 'server_form.connect.button.disabled' : 'server_form.connect.button';
|
||||
|
||||
return (
|
||||
|
|
@ -175,21 +156,17 @@ const ServerForm = ({
|
|||
testID={'server_form.display_help'}
|
||||
/>
|
||||
}
|
||||
<View style={styles.connectButtonContainer}>
|
||||
<Button
|
||||
containerStyle={styles.connectButton}
|
||||
disabled={buttonDisabled}
|
||||
onPress={onConnect}
|
||||
testID={connectButtonTestId}
|
||||
buttonStyle={styleButtonBackground}
|
||||
disabledStyle={styleButtonBackground}
|
||||
>
|
||||
{buttonIcon}
|
||||
<FormattedText
|
||||
defaultMessage={buttonText}
|
||||
id={buttonID}
|
||||
style={styleButtonText}
|
||||
size='lg'
|
||||
theme={theme}
|
||||
text={formatMessage(connecting ? messages.connecting : messages.connect)}
|
||||
showLoader={connecting}
|
||||
/>
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -187,22 +187,13 @@ exports[`SendTestNotificationNotice should match snapshot 1`] = `
|
|||
<Text
|
||||
numberOfLines={1}
|
||||
style={
|
||||
[
|
||||
[
|
||||
[
|
||||
{
|
||||
"color": "#ffffff",
|
||||
"fontFamily": "OpenSans-SemiBold",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
"lineHeight": 20,
|
||||
},
|
||||
{
|
||||
"color": "#ffffff",
|
||||
},
|
||||
],
|
||||
undefined,
|
||||
],
|
||||
]
|
||||
}
|
||||
}
|
||||
>
|
||||
Send a test notification
|
||||
|
|
@ -298,22 +289,13 @@ exports[`SendTestNotificationNotice should match snapshot 1`] = `
|
|||
<Text
|
||||
numberOfLines={1}
|
||||
style={
|
||||
[
|
||||
[
|
||||
[
|
||||
{
|
||||
"color": "#1c58d9",
|
||||
"fontFamily": "OpenSans-SemiBold",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
"lineHeight": 20,
|
||||
},
|
||||
{
|
||||
"color": "#1c58d9",
|
||||
},
|
||||
],
|
||||
undefined,
|
||||
],
|
||||
]
|
||||
}
|
||||
}
|
||||
>
|
||||
Troubleshooting docs
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Button} from '@rneui/base';
|
||||
import React from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {Text, View} from 'react-native';
|
||||
|
||||
import Button from '@components/button';
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {typography} from '@utils/typography';
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ interface AuthErrorProps {
|
|||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||
return {
|
||||
button: {
|
||||
buttonContainer: {
|
||||
marginTop: 25,
|
||||
},
|
||||
errorText: {
|
||||
|
|
@ -44,6 +44,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
|||
});
|
||||
|
||||
const AuthError = ({error, retry, theme}: AuthErrorProps) => {
|
||||
const intl = useIntl();
|
||||
const style = getStyleSheet(theme);
|
||||
|
||||
return (
|
||||
|
|
@ -57,17 +58,15 @@ const AuthError = ({error, retry, theme}: AuthErrorProps) => {
|
|||
<Text style={style.errorText}>
|
||||
{`${error}.`}
|
||||
</Text>
|
||||
<View style={style.buttonContainer}>
|
||||
<Button
|
||||
buttonStyle={[style.button, buttonBackgroundStyle(theme, 'lg', 'primary', 'default')]}
|
||||
testID='mobile.oauth.try_again'
|
||||
onPress={retry}
|
||||
>
|
||||
<FormattedText
|
||||
id='mobile.oauth.try_again'
|
||||
defaultMessage='Try again'
|
||||
style={buttonTextStyle(theme, 'lg', 'primary', 'default')}
|
||||
size='lg'
|
||||
text={intl.formatMessage({id: 'mobile.oauth.try_again', defaultMessage: 'Try again'})}
|
||||
theme={theme}
|
||||
/>
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,19 +1,17 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useCallback, useMemo} from 'react';
|
||||
import React, {useCallback} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {DeviceEventEmitter, StyleSheet, TouchableOpacity, View} from 'react-native';
|
||||
import {DeviceEventEmitter, StyleSheet, View} from 'react-native';
|
||||
|
||||
import {createDirectChannel, switchToChannelById} from '@actions/remote/channel';
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import Button from '@components/button';
|
||||
import OptionBox, {OPTIONS_HEIGHT} from '@components/option_box';
|
||||
import {Events, Screens} from '@constants';
|
||||
import {useServerUrl} from '@context/server';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {dismissBottomSheet} from '@screens/navigation';
|
||||
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
|
||||
|
||||
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||
|
||||
|
|
@ -45,9 +43,7 @@ const styles = StyleSheet.create({
|
|||
width: '100%',
|
||||
},
|
||||
singleContainer: {
|
||||
flexDirection: 'row',
|
||||
marginBottom: 20,
|
||||
width: '100%',
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -56,10 +52,6 @@ const UserProfileOptions = ({location, type, userId, username}: Props) => {
|
|||
const theme = useTheme();
|
||||
const serverUrl = useServerUrl();
|
||||
|
||||
const buttonStyle = useMemo(() => {
|
||||
return buttonBackgroundStyle(theme, 'lg', 'tertiary', 'default');
|
||||
}, [theme]);
|
||||
|
||||
const mentionUser = useCallback(async () => {
|
||||
await dismissBottomSheet(Screens.USER_PROFILE);
|
||||
DeviceEventEmitter.emit(Events.SEND_TO_POST_DRAFT, {location, text: `@${username}`});
|
||||
|
|
@ -80,7 +72,7 @@ const UserProfileOptions = ({location, type, userId, username}: Props) => {
|
|||
iconName='send'
|
||||
onPress={openChannel}
|
||||
testID='user_profile_options.send_message.option'
|
||||
text={intl.formatMessage({id: 'channel_info.send_mesasge', defaultMessage: 'Send message'})}
|
||||
text={intl.formatMessage({id: 'channel_info.send_a_mesasge', defaultMessage: 'Send message'})}
|
||||
/>
|
||||
<View style={styles.divider}/>
|
||||
<OptionBox
|
||||
|
|
@ -95,22 +87,15 @@ const UserProfileOptions = ({location, type, userId, username}: Props) => {
|
|||
|
||||
return (
|
||||
<View style={styles.singleContainer}>
|
||||
<TouchableOpacity
|
||||
style={[buttonStyle, styles.singleButton]}
|
||||
<Button
|
||||
onPress={openChannel}
|
||||
testID='user_profile_options.send_message.option'
|
||||
>
|
||||
<CompassIcon
|
||||
color={theme.buttonBg}
|
||||
name='send'
|
||||
style={styles.icon}
|
||||
size='lg'
|
||||
emphasis='tertiary'
|
||||
theme={theme}
|
||||
text={intl.formatMessage({id: 'channel_info.send_mesasge', defaultMessage: 'Send message'})}
|
||||
iconName='send'
|
||||
/>
|
||||
<FormattedText
|
||||
id='channel_info.send_a_mesasge'
|
||||
defaultMessage='Send a message'
|
||||
style={[buttonTextStyle(theme, 'lg', 'tertiary', 'default'), {marginLeft: 8}]}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -158,11 +158,17 @@ const UserProfile = ({
|
|||
'90%',
|
||||
];
|
||||
}, [
|
||||
headerText, showUserProfileOptions, showCustomStatus,
|
||||
showNickname, showPosition, showLocalTime,
|
||||
manageMode, bottom, showOptions,
|
||||
canChangeMemberRoles, canManageAndRemoveMembers,
|
||||
enableCustomAttributes,
|
||||
headerText,
|
||||
showUserProfileOptions,
|
||||
showCustomStatus,
|
||||
showNickname,
|
||||
showPosition,
|
||||
showLocalTime,
|
||||
manageMode,
|
||||
bottom,
|
||||
showOptions,
|
||||
canChangeMemberRoles,
|
||||
canManageAndRemoveMembers,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -464,6 +464,7 @@
|
|||
"load_channels_error.title": "Couldn't load {teamDisplayName}",
|
||||
"load_teams_error.message": "There was a problem loading content for this server.",
|
||||
"load_teams_error.title": "Couldn't load {serverName}",
|
||||
"loading_error.retry": "Retry",
|
||||
"login_mfa.enterToken": "To complete the sign in process, please enter the code from your mobile device's authenticator app.",
|
||||
"login_mfa.token": "Enter MFA Token",
|
||||
"login_mfa.tokenReq": "Please enter an MFA token",
|
||||
|
|
|
|||
Loading…
Reference in a new issue