User status in room summary card (#34239)

This commit is contained in:
David Baker
2026-07-14 08:56:03 +00:00
committed by GitHub
parent 2f612c3a9d
commit 732716ba12
4 changed files with 43 additions and 1 deletions
@@ -13,6 +13,7 @@ import {
RoomEvent,
RoomStateEvent,
} from "matrix-js-sdk/src/matrix";
import { type UserStatus } from "@element-hq/web-shared-components";
import { useMatrixClientContext } from "../../../contexts/MatrixClientContext";
import { useIsEncrypted } from "../../../hooks/useIsEncrypted";
@@ -41,9 +42,16 @@ import { usePinnedEvents } from "../../../hooks/usePinnedEvents";
import { tagRoom } from "../../../utils/room/tagRoom";
import { inviteToRoom } from "../../../utils/room/inviteToRoom";
import { getTagsForRoom } from "../../../utils/room/getTagsForRoom";
import { useDmMember } from "../../views/avatars/WithPresenceIndicator";
import { useUserStatus } from "../../../hooks/useUserStatus";
export interface RoomSummaryCardState {
isDirectMessage: boolean;
/**
* The MSC4426 status of the other user if this room is a DM.
* Should be undefined for non-DM rooms.
*/
userStatus: UserStatus | undefined;
/**
* Whether the room is encrypted, used to display the correct badge and icon
*/
@@ -182,6 +190,8 @@ export function useRoomSummaryCardViewModel(
const isFavorite = roomTags.includes(DefaultTagID.Favourite);
const isDirectMessage = useIsDirectMessage(room);
const dmMember = useDmMember(room);
const userStatus = useUserStatus(dmMember?.userId);
const onRoomMembersClick = (): void => {
RightPanelStore.instance.pushCard({ phase: RightPanelPhases.MemberList }, true);
@@ -261,6 +271,7 @@ export function useRoomSummaryCardViewModel(
return {
isDirectMessage,
userStatus,
isRoomEncrypted,
roomJoinRule,
e2eStatus,
@@ -39,7 +39,7 @@ import ErrorIcon from "@vector-im/compound-design-tokens/assets/web/icons/error"
import ErrorSolidIcon from "@vector-im/compound-design-tokens/assets/web/icons/error-solid";
import ChevronDownIcon from "@vector-im/compound-design-tokens/assets/web/icons/chevron-down";
import { JoinRule, type Room } from "matrix-js-sdk/src/matrix";
import { Box, Flex, HistoryVisibilityBadge, LinkedText } from "@element-hq/web-shared-components";
import { Box, Flex, HistoryVisibilityBadge, LinkedText, StatusTextView } from "@element-hq/web-shared-components";
import BaseCard from "./BaseCard.tsx";
import { _t } from "../../../languageHandler.tsx";
@@ -153,6 +153,7 @@ const RoomSummaryCardView: React.FC<IProps> = ({
>
{name}
</Heading>
{vm.userStatus && <StatusTextView status={vm.userStatus} />}
<Text
as="div"
size="sm"
@@ -55,6 +55,7 @@ describe("<RoomSummaryCard />", () => {
// Setup mock view models
const vmDefaultValues: RoomSummaryCardState = {
isDirectMessage: false,
userStatus: undefined,
isRoomEncrypted: false,
e2eStatus: undefined,
isVideoRoom: false,
@@ -325,4 +326,31 @@ describe("<RoomSummaryCard />", () => {
expect(screen.queryByText("Public room")).toBeInTheDocument();
});
});
describe("user status", () => {
it("shows the other user's status when set", () => {
mocked(useRoomSummaryCardViewModel).mockReturnValue({
...vmDefaultValues,
isDirectMessage: true,
userStatus: { emoji: "💬", text: "In a meeting" },
});
getComponent();
expect(screen.getByText("In a meeting")).toBeInTheDocument();
expect(screen.getByText("💬")).toBeInTheDocument();
});
it("does not show a status when there is none", () => {
mocked(useRoomSummaryCardViewModel).mockReturnValue({
...vmDefaultValues,
isDirectMessage: true,
userStatus: undefined,
});
getComponent();
expect(screen.queryByText("In a meeting")).not.toBeInTheDocument();
});
});
});
@@ -9,6 +9,7 @@
display: inline-flex;
align-items: center;
gap: var(--cpd-space-1x);
max-width: 100%;
span {
font: var(--cpd-font-body-md-medium);
@@ -18,6 +19,7 @@
.menuStatusText {
overflow: hidden;
min-width: 0;
white-space: nowrap;
text-overflow: ellipsis;
}
}