mattermost-mobile/app/hooks/use_tabs/tab.tsx
Daniel Espino García 6c53533080
Standardize tabs across different components (#8691)
* Standardize tabs across different components

* Add tests and minor fixes

* Remove unneeded tests

* Add missing change

* Fix test

* Refactor to remove the component from the hook

* Rename hasDot for requiresUserAttention.

* Apply the changes to scheduled posts

* Fix texts

* Fix tests and fix minor style issue on iOS

* Fix filter positioning

* Fix some e2e tests

* Fix tests

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2025-05-28 16:23:37 +02:00

121 lines
3.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 {TouchableOpacity, View} from 'react-native';
import Badge from '@components/badge';
import FormattedText from '@components/formatted_text';
import {useTheme} from '@context/theme';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import {typography} from '@utils/typography';
import type {MessageDescriptor} from 'react-intl';
const getStyleSheetFromTheme = makeStyleSheetFromTheme((theme) => {
return {
menuItemContainer: {
paddingVertical: 8,
paddingHorizontal: 16,
flexDirection: 'row',
gap: 4,
},
menuItemContainerSelected: {
backgroundColor: changeOpacity(theme.buttonBg, 0.08),
borderRadius: 4,
},
menuItem: {
color: changeOpacity(theme.centerChannelColor, 0.56),
alignSelf: 'center',
...typography('Body', 200, 'SemiBold'),
},
menuItemSelected: {
color: theme.buttonBg,
},
dot: {
position: 'absolute',
width: 6,
height: 6,
borderRadius: 3,
backgroundColor: theme.sidebarTextActiveBorder,
right: 8,
top: 8,
},
badge: {
position: undefined,
color: changeOpacity(theme.centerChannelColor, 0.75),
backgroundColor: changeOpacity(theme.centerChannelColor, 0.08),
alignSelf: 'center',
left: undefined,
top: undefined,
borderWidth: 0,
...typography('Body', 100, 'SemiBold'),
},
};
});
type TabProps<T extends string> = {
name: MessageDescriptor;
id: T;
requiresUserAttention?: boolean;
handleTabChange: (value: T) => void;
isSelected: boolean;
count?: number;
testID: string;
}
const Tab = <T extends string>({
name,
id,
requiresUserAttention,
handleTabChange,
isSelected,
count,
testID,
}: TabProps<T>) => {
const theme = useTheme();
const styles = getStyleSheetFromTheme(theme);
const onPress = useCallback(() => {
handleTabChange(id);
}, [handleTabChange, id]);
const containerStyle = useMemo(() => {
return isSelected ? [styles.menuItemContainer, styles.menuItemContainerSelected] : styles.menuItemContainer;
}, [isSelected, styles.menuItemContainer, styles.menuItemContainerSelected]);
const textStyle = useMemo(() => {
return isSelected ? [styles.menuItem, styles.menuItemSelected] : styles.menuItem;
}, [isSelected, styles.menuItem, styles.menuItemSelected]);
return (
<TouchableOpacity
key={id}
onPress={onPress}
testID={`${testID}.${id}.button`}
accessibilityState={{selected: isSelected}}
>
<View style={containerStyle}>
<FormattedText
{...name}
style={textStyle}
/>
{count ? (
<Badge
value={count}
visible={count !== 0}
testID={`${testID}.${id}.badge`}
style={styles.badge}
/>
) : null}
{requiresUserAttention ? (
<View
style={styles.dot}
testID={`${testID}.${id}.dot`}
/>
) : null}
</View>
</TouchableOpacity>
);
};
export default Tab;