mattermost-mobile-upstream/app/components/channel_list_row/index.tsx
Daniel Espino García 84ea188366
Mattermost Blocks (#9764)
* Mattermost Blocks

* Move block renderer to its own components folder

* Sync translation layer

* UX fixes

* Refactor button to use the button component

* Code review

* Fix CI

* Add animations to collapse blocks

* Add unit tests

* Add e2e tests and related fixes

* Address coderabbit comments

* Address UX comments

* Address feedback

* Address coderabbit comments

* Fix snapshots

* Sync with webapp translation

* Add node limit to button markdown node

* Address feedback

* i18n-extract

* Fix test

* Move image utils to the utils folder

* Remove unneeded style

* Revert build script change

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2026-06-29 18:42:16 +02:00

138 lines
3.6 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useMemo} from 'react';
import {
Text,
TouchableOpacity,
View,
} from 'react-native';
import CompassIcon, {type CompassIconName} from '@components/compass_icon';
import {useTheme} from '@context/theme';
import {makeStyleSheetFromTheme, changeOpacity} from '@utils/theme';
import {typography} from '@utils/typography';
type Props = {
channel: Channel;
onPress: (channel: Channel) => void;
testID?: string;
selectable?: boolean;
selected?: boolean;
}
const getStyleFromTheme = makeStyleSheetFromTheme((theme: Theme) => {
return {
titleContainer: {
marginLeft: 16,
flexDirection: 'column',
flex: 1,
flexShrink: 1,
minWidth: 0,
},
displayName: {
color: theme.centerChannelColor,
...typography('Body', 200),
},
icon: {
padding: 2,
color: changeOpacity(theme.centerChannelColor, 0.56),
},
container: {
flex: 1,
flexDirection: 'row',
},
outerContainer: {
paddingVertical: 9,
},
purpose: {
color: changeOpacity(theme.centerChannelColor, 0.64),
...typography('Body', 75),
flexShrink: 1,
},
};
});
export default function ChannelListRow({
channel,
onPress,
testID,
selectable = false,
selected = false,
}: Props) {
const theme = useTheme();
const style = getStyleFromTheme(theme);
const handlePress = () => {
onPress(channel);
};
const selectionIcon = useMemo(() => {
if (!selectable) {
return null;
}
const color = selected ? theme.buttonBg : theme.centerChannelColor;
return (
<View>
<CompassIcon
name={selected ? 'check-circle' : 'circle-outline'}
size={28}
color={color}
/>
</View>
);
}, [selectable, selected, theme]);
let purposeComponent;
if (channel.purpose) {
purposeComponent = (
<Text
style={style.purpose}
ellipsizeMode='tail'
numberOfLines={1}
>
{channel.purpose}
</Text>
);
}
const itemTestID = `${testID}.${channel.name}`;
const channelDisplayNameTestID = `${itemTestID}.display_name`;
let icon: CompassIconName = 'globe';
if (channel.delete_at) {
icon = 'archive-outline';
} else if (channel.shared) {
icon = 'circle-multiple-outline';
}
return (
<View style={style.outerContainer}>
<TouchableOpacity
onPress={handlePress}
>
<View
style={style.container}
testID={itemTestID}
>
<CompassIcon
name={icon}
size={20}
style={style.icon}
/>
<View style={style.titleContainer}>
<Text
style={style.displayName}
testID={channelDisplayNameTestID}
>
{channel.display_name}
</Text>
{purposeComponent}
</View>
{selectionIcon}
</View>
</TouchableOpacity>
</View>
);
}