import { Box, Button, color, config, Text, toRem } from 'folds'; import { Icon, Icons } from '../icons'; import React from 'react'; import { useNavigate } from 'react-router-dom'; import { UserHero, UserHeroName } from './UserHero'; import { getMxIdServer, mxcUrlToHttp } from '../../utils/matrix'; import { getMemberAvatarMxc, getMemberDisplayName } from '../../utils/room'; import { useMatrixClient } from '../../hooks/useMatrixClient'; import { useMediaAuthentication } from '../../hooks/useMediaAuthentication'; import { usePowerLevels } from '../../hooks/usePowerLevels'; import { useRoom } from '../../hooks/useRoom'; import { useUserPresence } from '../../hooks/useUserPresence'; import { useOtherUserProfileStyle } from '../../hooks/useUserProfileStyle'; import { IgnoredUserAlert, MutualRoomsChip, OptionsChip, ServerChip, ShareChip } from './UserChips'; import { useCloseUserRoomProfile } from '../../state/hooks/userRoomProfile'; import { PowerChip } from './PowerChip'; import { UserInviteAlert, UserBanAlert, UserModeration, UserKickAlert } from './UserModeration'; import { useIgnoredUsers } from '../../hooks/useIgnoredUsers'; import { useMembership } from '../../hooks/useMembership'; import { Membership } from '../../../types/matrix/room'; import { useRoomCreators } from '../../hooks/useRoomCreators'; import { useRoomPermissions } from '../../hooks/useRoomPermissions'; import { useMemberPowerCompare } from '../../hooks/useMemberPowerCompare'; import { CreatorChip } from './CreatorChip'; import { getDirectCreatePath, withSearchParam } from '../../pages/pathUtils'; import { DirectCreateSearchParams } from '../../pages/paths'; import { getContrastingTextColor, stripAlphaFromColor, getTextShadowColor } from '../../utils/common'; import classNames from 'classnames'; import { BreakWord, LineClamp3 } from '../../styles/Text.css'; import colorMXID, { getColorMXIDValue } from '../../../util/colorMXID'; import { useOtherUserColor } from '../../hooks/useUserColor'; type UserRoomProfileProps = { userId: string; }; export function UserRoomProfile({ userId }: UserRoomProfileProps) { const mx = useMatrixClient(); const useAuthentication = useMediaAuthentication(); const navigate = useNavigate(); const closeUserRoomProfile = useCloseUserRoomProfile(); const ignoredUsers = useIgnoredUsers(); const ignored = ignoredUsers.includes(userId); const room = useRoom(); const powerLevels = usePowerLevels(room); const creators = useRoomCreators(room); const permissions = useRoomPermissions(creators, powerLevels); const { hasMorePower } = useMemberPowerCompare(creators, powerLevels); const myUserId = mx.getSafeUserId(); const creator = creators.has(userId); const canKickUser = permissions.action('kick', myUserId) && hasMorePower(myUserId, userId); const canBanUser = permissions.action('ban', myUserId) && hasMorePower(myUserId, userId); const canUnban = permissions.action('ban', myUserId); const canInvite = permissions.action('invite', myUserId); const member = room.getMember(userId); const membership = useMembership(room, userId); const server = getMxIdServer(userId); const displayName = getMemberDisplayName(room, userId); const avatarMxc = getMemberAvatarMxc(room, userId); const avatarUrl = (avatarMxc && mxcUrlToHttp(mx, avatarMxc, useAuthentication)) ?? undefined; const presence = useUserPresence(userId); const profileStyle = useOtherUserProfileStyle(userId, avatarMxc); const userColor = useOtherUserColor(userId, avatarMxc); // Build gradient CSS if configured const gradientStyle = profileStyle.gradient ? `linear-gradient(${profileStyle.gradient.direction}, ${profileStyle.gradient.startColor}, ${profileStyle.gradient.stopColor})` : undefined; const handleMessage = () => { closeUserRoomProfile(); const directSearchParam: DirectCreateSearchParams = { userId, }; navigate(withSearchParam(getDirectCreatePath(), directSearchParam)); }; const hasBottomContent = ignored || (!!member && membership === Membership.Ban) || (!!member && membership === Membership.Leave && !!member.events.member && member.events.member.getSender() !== userId) || (!!member && membership === Membership.Invite) || (canInvite && membership === Membership.Leave) || (canKickUser && membership === Membership.Join) || (canBanUser && membership !== Membership.Ban); // Use userColor for text, or fall back to colorMXID const profileColor = userColor ? userColor : getColorMXIDValue(userId); const profileTextShadow = `0 1px 4px ${getTextShadowColor(profileColor)}`; // Use avatarBorderColor for pill background only if it has visible alpha (not fully transparent) const hasVisibleBorder = profileStyle.avatarBorderColor && !profileStyle.avatarBorderColor.endsWith('00'); const pillBgColor = hasVisibleBorder ? stripAlphaFromColor(profileStyle.avatarBorderColor!) : undefined; console.log('[UserRoomProfile]', { userId, avatarMxc, userColor, profileStyle, profileColor, profileTextShadow, hasVisibleBorder, pillBgColor, fallbackColorMXID: getColorMXIDValue(userId), }); return ( {/* Display Name */} {getMemberDisplayName(room, userId)} {/* Username */} {userId} {/* Status Pill */} {presence?.status && ( {presence.status} )} {/* Chips Row */} {server && } {creator ? : } {/* Message Button */} {userId !== myUserId && ( )} {/* Additional Chips if needed */} {userId !== myUserId && ( )} {hasBottomContent && {ignored && } {member && membership === Membership.Ban && ( )} {member && membership === Membership.Leave && member.events.member && member.events.member.getSender() !== userId && ( )} {member && membership === Membership.Invite && ( )} } ); }