diff --git a/apps/web/src/components/viewmodels/right_panel/RoomSummaryCardViewModel.tsx b/apps/web/src/components/viewmodels/right_panel/RoomSummaryCardViewModel.tsx index d336dc42e5..903066f65b 100644 --- a/apps/web/src/components/viewmodels/right_panel/RoomSummaryCardViewModel.tsx +++ b/apps/web/src/components/viewmodels/right_panel/RoomSummaryCardViewModel.tsx @@ -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, diff --git a/apps/web/src/components/views/right_panel/RoomSummaryCardView.tsx b/apps/web/src/components/views/right_panel/RoomSummaryCardView.tsx index 23d858e414..320d12dee3 100644 --- a/apps/web/src/components/views/right_panel/RoomSummaryCardView.tsx +++ b/apps/web/src/components/views/right_panel/RoomSummaryCardView.tsx @@ -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 = ({ > {name} + {vm.userStatus && } ", () => { // Setup mock view models const vmDefaultValues: RoomSummaryCardState = { isDirectMessage: false, + userStatus: undefined, isRoomEncrypted: false, e2eStatus: undefined, isVideoRoom: false, @@ -325,4 +326,31 @@ describe("", () => { 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(); + }); + }); }); diff --git a/packages/shared-components/src/status/StatusTextView.module.css b/packages/shared-components/src/status/StatusTextView.module.css index 2437172197..7b584b4f5c 100644 --- a/packages/shared-components/src/status/StatusTextView.module.css +++ b/packages/shared-components/src/status/StatusTextView.module.css @@ -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; } }