diff --git a/lib/shared/user-utils.js b/lib/shared/user-utils.js index 76fc31c99..c97e9c404 100644 --- a/lib/shared/user-utils.js +++ b/lib/shared/user-utils.js @@ -1,31 +1,52 @@ // @flow import bots from '../facts/bots'; import staff from '../facts/staff'; -import type { RelativeMemberInfo } from '../types/thread-types'; -import type { RelativeUserInfo } from '../types/user-types'; +import type { + ServerThreadInfo, + RawThreadInfo, + RelativeMemberInfo, + ThreadInfo, +} from '../types/thread-types'; +import type { + RelativeUserInfo, + UserInfo, + UserInfos, +} from '../types/user-types'; +import { memberHasAdminPowers } from './thread-utils'; function stringForUser(user: RelativeUserInfo | RelativeMemberInfo): string { if (user.isViewer) { return 'you'; } else if (user.username) { return user.username; } else { return 'anonymous'; } } function isStaff(userID: string): boolean { if (staff.includes(userID)) { return true; } for (const key in bots) { const bot = bots[key]; if (userID === bot.userID) { return true; } } return false; } -export { stringForUser, isStaff }; +function getKeyserverAdmin( + community: ThreadInfo | RawThreadInfo | ServerThreadInfo, + userInfos: UserInfos, +): ?UserInfo { + // This hack only works as long as there is only one admin + // Linear task to revert this: + // https://linear.app/comm/issue/ENG-1707/revert-fix-getting-the-keyserver-admin-info + const admin = community.members.find(memberHasAdminPowers); + return admin ? userInfos[admin.id] : undefined; +} + +export { stringForUser, isStaff, getKeyserverAdmin }; diff --git a/native/components/community-pill.react.js b/native/components/community-pill.react.js index cd1913780..3eca56b4b 100644 --- a/native/components/community-pill.react.js +++ b/native/components/community-pill.react.js @@ -1,73 +1,70 @@ // @flow import * as React from 'react'; import { View, StyleSheet } from 'react-native'; -import { memberHasAdminPowers } from 'lib/shared/thread-utils'; -import type { ThreadInfo, RelativeMemberInfo } from 'lib/types/thread-types'; +import { getKeyserverAdmin } from 'lib/shared/user-utils'; +import type { ThreadInfo } from 'lib/types/thread-types'; import { useSelector } from '../redux/redux-utils'; import { useColors } from '../themes/colors'; import CommIcon from './comm-icon.react'; import Pill from './pill.react'; import ThreadPill from './thread-pill.react'; type Props = { +community: ThreadInfo, }; function CommunityPill(props: Props): React.Node { const { community } = props; const userInfos = useSelector(state => state.userStore.userInfos); - const keyserverOperatorUsername: ?string = React.useMemo(() => { - for (const member: RelativeMemberInfo of community.members) { - if (memberHasAdminPowers(member)) { - return userInfos[member.id].username; - } - } - }, [community, userInfos]); + const keyserverOperatorUsername: ?string = React.useMemo( + () => getKeyserverAdmin(community, userInfos)?.username, + [community, userInfos], + ); const colors = useColors(); const keyserverOperatorLabel: ?React.Node = React.useMemo(() => { if (!keyserverOperatorUsername) { return undefined; } const icon = ( ); return ( ); }, [ colors.codeBackground, colors.panelForegroundLabel, keyserverOperatorUsername, ]); return ( {keyserverOperatorLabel} ); } const styles = StyleSheet.create({ container: { flexDirection: 'row', }, }); export default CommunityPill; diff --git a/web/chat/chat-thread-ancestors.react.js b/web/chat/chat-thread-ancestors.react.js index 3a4cfaddf..85d17f816 100644 --- a/web/chat/chat-thread-ancestors.react.js +++ b/web/chat/chat-thread-ancestors.react.js @@ -1,131 +1,128 @@ // @flow import classNames from 'classnames'; import * as React from 'react'; import { useAncestorThreads } from 'lib/shared/ancestor-threads'; -import { memberHasAdminPowers, colorIsDark } from 'lib/shared/thread-utils'; +import { colorIsDark } from 'lib/shared/thread-utils'; +import { getKeyserverAdmin } from 'lib/shared/user-utils'; import type { ThreadInfo } from 'lib/types/thread-types'; import CommIcon from '../CommIcon.react'; import { useSelector } from '../redux/redux-utils'; import SWMansionIcon from '../SWMansionIcon.react'; import css from './chat-thread-ancestors.css'; const SHOW_SEE_FULL_STRUCTURE = false; type ThreadAncestorsProps = { +threadInfo: ThreadInfo, }; function ThreadAncestors(props: ThreadAncestorsProps): React.Node { const { threadInfo } = props; const { color: threadColor } = threadInfo; const darkColor = colorIsDark(threadColor); const threadColorStyle = React.useMemo( () => ({ backgroundColor: `#${threadColor}`, color: darkColor ? 'var(--thread-ancestor-color-light)' : 'var(--thread-ancestor-color-dark)', }), [darkColor, threadColor], ); const fullStructureButtonColorStyle = React.useMemo( () => ({ color: `#${threadColor}` }), [threadColor], ); const ancestorThreads = useAncestorThreads(threadInfo); const userInfos = useSelector(state => state.userStore.userInfos); const community = ancestorThreads[0] ?? threadInfo; - const keyserverOwnerUsername: ?string = React.useMemo(() => { - for (const member of community.members) { - if (memberHasAdminPowers(member)) { - return userInfos[member.id].username; - } - } - return undefined; - }, [community.members, userInfos]); + const keyserverOwnerUsername: ?string = React.useMemo( + () => getKeyserverAdmin(community, userInfos)?.username, + [community, userInfos], + ); const keyserverInfo = React.useMemo( () => (
{keyserverOwnerUsername}
{community.uiName}
), [community.uiName, keyserverOwnerUsername, threadColorStyle], ); const middlePath = React.useMemo(() => { if (ancestorThreads.length < 2) { return null; } return ( <>
); }, [ancestorThreads.length, threadColorStyle]); const threadHasNoAncestors = community === threadInfo; const currentThread = React.useMemo(() => { if (threadHasNoAncestors) { return null; } return ( <>
{threadInfo.uiName}
); }, [threadHasNoAncestors, threadColorStyle, threadInfo.uiName]); let seeFullStructure = null; if (SHOW_SEE_FULL_STRUCTURE) { seeFullStructure = ( ); } return ( <>
{keyserverInfo} {middlePath} {currentThread}
{seeFullStructure} ); } export default ThreadAncestors;