// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import React, {useCallback, useMemo, type ReactNode} from 'react'; import {useIntl} from 'react-intl'; import {StyleSheet, Text, TouchableOpacity, View, type StyleProp, type ViewStyle} from 'react-native'; import CompassIcon from '@components/compass_icon'; import CustomStatusEmoji from '@components/custom_status/custom_status_emoji'; import ProfilePicture from '@components/profile_picture'; import {BotTag, GuestTag} from '@components/tag'; import {useTheme} from '@context/theme'; import {nonBreakingString} from '@utils/strings'; import {makeStyleSheetFromTheme, changeOpacity} from '@utils/theme'; import {typography} from '@utils/typography'; import {displayUsername, getUserCustomStatus, isBot, isCustomStatusExpired, isDeactivated, isGuest, isShared} from '@utils/user'; import type UserModel from '@typings/database/models/servers/user'; type Props = { FooterComponent?: ReactNode; user?: UserProfile | UserModel; containerStyle?: StyleProp; currentUserId: string; includeMargin?: boolean; size?: number; testID?: string; isCustomStatusEnabled: boolean; showBadges?: boolean; locale?: string; teammateNameDisplay: string; rightDecorator?: React.ReactNode; onUserPress?: (user: UserProfile | UserModel) => void; onUserLongPress?: (user: UserProfile | UserModel) => void; onLayout?: () => void; disabled?: boolean; viewRef?: React.LegacyRef; padding?: number; hideGuestTags: boolean; } const getThemedStyles = makeStyleSheetFromTheme((theme: Theme) => { return { rowPicture: { marginRight: 10, marginLeft: 2, width: 24, alignItems: 'center', justifyContent: 'center', }, rowFullname: { ...typography('Body', 200), color: theme.centerChannelColor, flex: 0, flexShrink: 1, }, rowUsername: { ...typography('Body', 100), color: changeOpacity(theme.centerChannelColor, 0.64), }, }; }); const nonThemedStyles = StyleSheet.create({ row: { height: 40, paddingBottom: 8, paddingTop: 4, flexDirection: 'row', alignItems: 'center', }, margin: {marginVertical: 8}, rowInfoBaseContainer: { flex: 1, }, rowInfoContainer: { flex: 1, flexDirection: 'row', alignItems: 'center', gap: 4, }, profile: { marginRight: 12, }, flex: { flex: 1, }, }); const UserItem = ({ FooterComponent, user, containerStyle, currentUserId, size = 24, testID, isCustomStatusEnabled, showBadges = false, locale, teammateNameDisplay, rightDecorator, onLayout, onUserPress, onUserLongPress, disabled = false, viewRef, padding, includeMargin, hideGuestTags, }: Props) => { const theme = useTheme(); const style = getThemedStyles(theme); const intl = useIntl(); const bot = user ? isBot(user) : false; const guest = user ? isGuest(user.roles) : false; const shared = user ? isShared(user) : false; const deactivated = user ? isDeactivated(user) : false; const isCurrentUser = currentUserId === user?.id; const customStatus = getUserCustomStatus(user); const customStatusExpired = isCustomStatusExpired(user); let displayName = displayUsername(user, locale, teammateNameDisplay); const showTeammateDisplay = displayName !== user?.username; if (isCurrentUser) { displayName = intl.formatMessage({id: 'channel_header.directchannel.you', defaultMessage: '{displayName} (you)'}, {displayName}); } const userItemTestId = `${testID}.${user?.id}`; const containerViewStyle = useMemo(() => { return [ nonThemedStyles.row, { opacity: disabled ? 0.32 : 1, paddingHorizontal: padding || undefined, }, includeMargin && nonThemedStyles.margin, ]; }, [disabled, padding, includeMargin]); const onPress = useCallback(() => { if (user) { onUserPress?.(user); } }, [user, onUserPress]); const onLongPress = useCallback(() => { if (user) { onUserLongPress?.(user); } }, [user, onUserLongPress]); return ( {nonBreakingString(displayName)} {Boolean(showTeammateDisplay) && Boolean(user?.username) && ( {nonBreakingString(` @${user?.username}`)} )} {deactivated && ( {nonBreakingString(` ${intl.formatMessage({id: 'mobile.user_list.deactivated', defaultMessage: 'Deactivated'})}`)} )} {showBadges && bot && ( )} {showBadges && guest && !hideGuestTags && ( )} {Boolean(isCustomStatusEnabled && !bot && customStatus?.emoji && !customStatusExpired) && ( )} {shared && ( )} {Boolean(rightDecorator) && rightDecorator} {FooterComponent} ); }; export default UserItem;