New room list: fix incorrect decoration (#29770)
* fix(call): reset call value when the roomId changes * fix(call): reset presence indicator when the room changes * refactor: use existing `usePresence` * test: fix room avatar view test * test: update snapshots
This commit is contained in:
@@ -5,32 +5,11 @@
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import {
|
||||
EventType,
|
||||
JoinRule,
|
||||
type MatrixEvent,
|
||||
type Room,
|
||||
RoomEvent,
|
||||
type User,
|
||||
UserEvent,
|
||||
} from "matrix-js-sdk/src/matrix";
|
||||
import { EventType, JoinRule, type MatrixEvent, type Room, RoomEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
|
||||
import DMRoomMap from "../../../utils/DMRoomMap";
|
||||
import { getJoinedNonFunctionalMembers } from "../../../utils/room/getJoinedNonFunctionalMembers";
|
||||
import { BUSY_PRESENCE_NAME } from "../../views/rooms/PresenceLabel";
|
||||
import { isPresenceEnabled } from "../../../utils/presence";
|
||||
|
||||
/**
|
||||
* The presence of a user in a DM room.
|
||||
* - "online": The user is online.
|
||||
* - "offline": The user is offline.
|
||||
* - "busy": The user is busy.
|
||||
* - "unavailable": the presence is unavailable.
|
||||
* - null: the user is not in a DM room or presence is not enabled.
|
||||
*/
|
||||
export type Presence = "online" | "offline" | "busy" | "unavailable" | null;
|
||||
import { useDmMember, usePresence, type Presence } from "../../views/avatars/WithPresenceIndicator";
|
||||
|
||||
export interface RoomAvatarViewState {
|
||||
/**
|
||||
@@ -50,7 +29,7 @@ export interface RoomAvatarViewState {
|
||||
* The presence of the user in the DM room.
|
||||
* If null, the user is not in a DM room or presence is not enabled.
|
||||
*/
|
||||
presence: Presence;
|
||||
presence: Presence | null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,7 +38,8 @@ export interface RoomAvatarViewState {
|
||||
*/
|
||||
export function useRoomAvatarViewModel(room: Room): RoomAvatarViewState {
|
||||
const isVideoRoom = room.isElementVideoRoom() || room.isCallRoom();
|
||||
const presence = useDMPresence(room);
|
||||
const roomMember = useDmMember(room);
|
||||
const presence = usePresence(room, roomMember);
|
||||
const isPublic = useIsPublic(room);
|
||||
|
||||
const hasDecoration = isPublic || isVideoRoom || presence !== null;
|
||||
@@ -97,48 +77,3 @@ function useIsPublic(room: Room): boolean {
|
||||
function isRoomPublic(room: Room): boolean {
|
||||
return room.getJoinRule() === JoinRule.Public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook listening to the presence of the DM user.
|
||||
* @param room
|
||||
*/
|
||||
function useDMPresence(room: Room): Presence {
|
||||
const dmUser = getDMUser(room);
|
||||
const [presence, setPresence] = useState<Presence>(getPresence(dmUser));
|
||||
useTypedEventEmitter(dmUser, UserEvent.Presence, () => setPresence(getPresence(dmUser)));
|
||||
useTypedEventEmitter(dmUser, UserEvent.CurrentlyActive, () => setPresence(getPresence(dmUser)));
|
||||
|
||||
return presence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DM user of the room.
|
||||
* Return undefined if the room is not a DM room, if we can't find the user or if the presence is not enabled.
|
||||
* @param room
|
||||
* @returns found user
|
||||
*/
|
||||
function getDMUser(room: Room): User | undefined {
|
||||
const otherUserId = DMRoomMap.shared().getUserIdForRoomId(room.roomId);
|
||||
if (!otherUserId) return;
|
||||
if (getJoinedNonFunctionalMembers(room).length !== 2) return;
|
||||
if (!isPresenceEnabled(room.client)) return;
|
||||
|
||||
return room.client.getUser(otherUserId) || undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the presence of the DM user.
|
||||
* @param dmUser
|
||||
*/
|
||||
function getPresence(dmUser: User | undefined): Presence {
|
||||
if (!dmUser) return null;
|
||||
if (BUSY_PRESENCE_NAME.matches(dmUser.presence)) return "busy";
|
||||
|
||||
const isOnline = dmUser.currentlyActive || dmUser.presence === "online";
|
||||
if (isOnline) return "online";
|
||||
|
||||
if (dmUser.presence === "offline") return "offline";
|
||||
if (dmUser.presence === "unavailable") return "unavailable";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -15,8 +15,9 @@ import BusyIcon from "@vector-im/compound-design-tokens/assets/web/icons/presenc
|
||||
import classNames from "classnames";
|
||||
|
||||
import RoomAvatar from "./RoomAvatar";
|
||||
import { useRoomAvatarViewModel, type Presence } from "../../viewmodels/avatars/RoomAvatarViewModel";
|
||||
import { useRoomAvatarViewModel } from "../../viewmodels/avatars/RoomAvatarViewModel";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import { Presence } from "./WithPresenceIndicator";
|
||||
|
||||
interface RoomAvatarViewProps {
|
||||
/**
|
||||
@@ -83,7 +84,7 @@ type PresenceDecorationProps = {
|
||||
*/
|
||||
function PresenceDecoration({ presence }: PresenceDecorationProps): JSX.Element {
|
||||
switch (presence) {
|
||||
case "online":
|
||||
case Presence.Online:
|
||||
return (
|
||||
<OnlineOrUnavailableIcon
|
||||
width="8px"
|
||||
@@ -93,7 +94,7 @@ function PresenceDecoration({ presence }: PresenceDecorationProps): JSX.Element
|
||||
aria-label={_t("presence|online")}
|
||||
/>
|
||||
);
|
||||
case "unavailable":
|
||||
case Presence.Away:
|
||||
return (
|
||||
<OnlineOrUnavailableIcon
|
||||
width="8px"
|
||||
@@ -103,7 +104,7 @@ function PresenceDecoration({ presence }: PresenceDecorationProps): JSX.Element
|
||||
aria-label={_t("presence|away")}
|
||||
/>
|
||||
);
|
||||
case "offline":
|
||||
case Presence.Offline:
|
||||
return (
|
||||
<OfflineIcon
|
||||
width="8px"
|
||||
@@ -113,7 +114,7 @@ function PresenceDecoration({ presence }: PresenceDecorationProps): JSX.Element
|
||||
aria-label={_t("presence|offline")}
|
||||
/>
|
||||
);
|
||||
case "busy":
|
||||
case Presence.Busy:
|
||||
return (
|
||||
<BusyIcon
|
||||
width="8px"
|
||||
|
||||
@@ -26,7 +26,7 @@ interface Props {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
enum Presence {
|
||||
export enum Presence {
|
||||
// Note: the names here are used in CSS class names
|
||||
Online = "ONLINE",
|
||||
Away = "AWAY",
|
||||
@@ -86,7 +86,7 @@ function getPresence(member: RoomMember | null): Presence | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
const usePresence = (room: Room, member: RoomMember | null): Presence | null => {
|
||||
export const usePresence = (room: Room, member: RoomMember | null): Presence | null => {
|
||||
const [presence, setPresence] = useState<Presence | null>(getPresence(member));
|
||||
const updatePresence = (): void => {
|
||||
setPresence(getPresence(member));
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { useState, useCallback, useMemo } from "react";
|
||||
import { useState, useCallback, useMemo, useEffect } from "react";
|
||||
|
||||
import type { RoomMember } from "matrix-js-sdk/src/matrix";
|
||||
import { type Call, ConnectionState, CallEvent } from "../models/Call";
|
||||
@@ -20,6 +20,12 @@ export const useCall = (roomId: string): Call | null => {
|
||||
useEventEmitter(CallStore.instance, CallStoreEvent.Call, (call: Call | null, forRoomId: string) => {
|
||||
if (forRoomId === roomId) setCall(call);
|
||||
});
|
||||
|
||||
// Reset the value when the roomId changes
|
||||
useEffect(() => {
|
||||
setCall(CallStore.instance.getCall(roomId));
|
||||
}, [roomId]);
|
||||
|
||||
return call;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user