mattermost-mobile/app/components/option_item/index.tsx
Avinash Lingaloo e443a69265
MM-45344 Gekidou Remove <MenuItem/> (#6522)
* added MENU_ITEM_HEIGHT to constant/view

* fix user presence and your profile

* added MENU_ITEM_HEIGHT to constant/view

* fix user presence and your profile

* UI Polish - Custom Status

* UI Polish - Settings

* UI Polish - logout

* refactored styles

* removed 'throws DataOperatorException' from './database/`

* fix for copy link option

* fix autoresponder

1.  user should be allowed to enter paragraph

2. the OOO was not immediately being updated on the notification main screen.  The fix is to cal fetchStatusInBatch after the updateMe operation

* About Screen - code clean up

* removed MenuItem component from common_post_options

* removed MenuItem from Settings

* refactored show_more and recent_item

* removed menu_item component

* Update setting_container.tsx

* PR review correction

* Update setting_container.tsx

* Update recent_item.tsx
2022-08-04 12:26:27 +04:00

286 lines
8.6 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useCallback, useMemo} from 'react';
import {Platform, StyleProp, Switch, Text, TextStyle, TouchableOpacity, View, ViewStyle} from 'react-native';
import CompassIcon from '@components/compass_icon';
import TouchableWithFeedback from '@components/touchable_with_feedback';
import {useTheme} from '@context/theme';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import {typography} from '@utils/typography';
import RadioItem, {RadioItemProps} from './radio_item';
const TouchableOptionTypes = {
ARROW: 'arrow',
DEFAULT: 'default',
RADIO: 'radio',
REMOVE: 'remove',
SELECT: 'select',
};
const OptionType = {
NONE: 'none',
TOGGLE: 'toggle',
...TouchableOptionTypes,
} as const;
type OptionType = typeof OptionType[keyof typeof OptionType];
export const ITEM_HEIGHT = 48;
const hitSlop = {top: 11, bottom: 11, left: 11, right: 11};
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
return {
actionContainer: {
flexDirection: 'row',
alignItems: 'center',
marginLeft: 16,
},
container: {
flexDirection: 'row',
alignItems: 'center',
minHeight: ITEM_HEIGHT,
},
destructive: {
color: theme.dndIndicator,
},
description: {
color: changeOpacity(theme.centerChannelColor, 0.64),
...typography('Body', 75),
marginTop: 2,
},
iconContainer: {marginRight: 16},
infoContainer: {marginRight: 2},
info: {
color: changeOpacity(theme.centerChannelColor, 0.56),
...typography('Body', 100),
},
inlineLabel: {
flexDirection: 'row',
flexShrink: 1,
justifyContent: 'center',
},
inlineLabelText: {
color: theme.centerChannelColor,
...typography('Body', 200, 'SemiBold'),
},
inlineDescription: {
color: theme.centerChannelColor,
...typography('Body', 200),
},
label: {
flexShrink: 1,
justifyContent: 'center',
},
labelContainer: {
flexDirection: 'row',
alignItems: 'center',
},
labelText: {
color: theme.centerChannelColor,
...typography('Body', 200),
},
removeContainer: {
flex: 1,
alignItems: 'flex-end',
color: theme.centerChannelColor,
marginRight: 20,
...typography('Body', 200),
},
row: {
flex: 1,
flexDirection: 'row',
},
};
});
export type OptionItemProps = {
action?: (React.Dispatch<React.SetStateAction<string | boolean>>)|((value: string | boolean) => void);
arrowStyle?: StyleProp<ViewStyle>;
containerStyle?: StyleProp<ViewStyle>;
description?: string;
destructive?: boolean;
icon?: string;
info?: string;
inline?: boolean;
label: string;
onRemove?: () => void;
optionDescriptionTextStyle?: StyleProp<TextStyle>;
optionLabelTextStyle?: StyleProp<TextStyle>;
radioItemProps?: Partial<RadioItemProps>;
selected?: boolean;
testID?: string;
type: OptionType;
value?: string;
}
const OptionItem = ({
action,
arrowStyle,
containerStyle,
description,
destructive,
icon,
info,
inline = false,
label,
onRemove,
optionDescriptionTextStyle,
optionLabelTextStyle,
radioItemProps,
selected,
testID = 'optionItem',
type,
value,
}: OptionItemProps) => {
const theme = useTheme();
const styles = getStyleSheet(theme);
const isInLine = inline && Boolean(description);
const labelStyle = useMemo(() => {
return isInLine ? styles.inlineLabel : styles.label;
}, [inline, styles, isInLine]);
const labelTextStyle = useMemo(() => {
return [
isInLine ? styles.inlineLabelText : styles.labelText,
destructive && styles.destructive,
];
}, [destructive, styles, isInLine]);
const descriptionTextStyle = useMemo(() => {
return [
isInLine ? styles.inlineDescription : styles.description,
destructive && styles.destructive,
];
}, [destructive, styles, isInLine]);
let actionComponent;
let radioComponent;
if (type === OptionType.SELECT && selected) {
actionComponent = (
<CompassIcon
color={theme.linkColor}
name='check'
size={24}
testID={`${testID}.selected`}
/>
);
} else if (type === OptionType.RADIO) {
radioComponent = (
<RadioItem
selected={Boolean(selected)}
{...radioItemProps}
/>
);
} else if (type === OptionType.TOGGLE) {
const trackColor = Platform.select({
ios: {true: theme.buttonBg, false: changeOpacity(theme.centerChannelColor, 0.16)},
default: {true: changeOpacity(theme.buttonBg, 0.32), false: changeOpacity(theme.centerChannelColor, 0.24)},
});
const thumbColor = Platform.select({
android: selected ? theme.buttonBg : '#F3F3F3', // Hardcoded color specified in ticket MM-45143
});
actionComponent = (
<Switch
onValueChange={action}
value={selected}
trackColor={trackColor}
thumbColor={thumbColor}
testID={`${testID}.toggled.${selected}`}
/>
);
} else if (type === OptionType.ARROW) {
actionComponent = (
<CompassIcon
color={changeOpacity(theme.centerChannelColor, 0.32)}
name='chevron-right'
size={24}
style={arrowStyle}
/>
);
} else if (type === OptionType.REMOVE) {
actionComponent = (
<TouchableWithFeedback
hitSlop={hitSlop}
onPress={onRemove}
style={[styles.iconContainer]}
type='opacity'
>
<CompassIcon
name={'close'}
size={18}
color={changeOpacity(theme.centerChannelColor, 0.64)}
/>
</TouchableWithFeedback>
);
}
const onPress = useCallback(() => {
action?.(value || '');
}, [value, action]);
const component = (
<View
testID={testID}
style={[styles.container, containerStyle]}
>
<View style={styles.row}>
<View style={styles.labelContainer}>
{Boolean(icon) && (
<View style={styles.iconContainer}>
<CompassIcon
name={icon!}
size={24}
color={destructive ? theme.dndIndicator : changeOpacity(theme.centerChannelColor, 0.64)}
/>
</View>
)}
{type === OptionType.RADIO && radioComponent}
<View style={labelStyle}>
<Text
style={[labelTextStyle, optionLabelTextStyle]}
testID={`${testID}.label`}
>
{label}
</Text>
{Boolean(description) &&
<Text
style={[descriptionTextStyle, optionDescriptionTextStyle]}
testID={`${testID}.description`}
>
{description}
</Text>
}
</View>
</View>
</View>
{Boolean(actionComponent || info) &&
<View style={styles.actionContainer}>
{
Boolean(info) &&
<View style={styles.infoContainer}>
<Text style={[styles.info, destructive && {color: theme.dndIndicator}]}>{info}</Text>
</View>
}
{actionComponent}
</View>
}
</View>
);
if (Object.values(TouchableOptionTypes).includes(type)) {
return (
<TouchableOpacity onPress={onPress}>
{component}
</TouchableOpacity>
);
}
return component;
};
export default OptionItem;