Files
cinny/src/app/hooks/useRoomMeta.ts
T

141 lines
4.3 KiB
TypeScript
Raw Normal View History

import { useCallback, useEffect, useState } from 'react';
import { RoomJoinRulesEventContent } from 'matrix-js-sdk/lib/types';
import { ClientEvent, MatrixEvent, Room, RoomEvent, RoomEventHandlerMap } from 'matrix-js-sdk';
import { StateEvent } from '../../types/matrix/room';
import { useStateEvent } from './useStateEvent';
import { useMatrixClient } from './useMatrixClient';
export const useRoomAvatar = (room: Room, dm?: boolean): string | undefined => {
const avatarEvent = useStateEvent(room, StateEvent.RoomAvatar);
if (dm) {
return room.getAvatarFallbackMember()?.getMxcAvatarUrl();
}
const content = avatarEvent?.getContent();
const avatarMxc = content && typeof content.url === 'string' ? content.url : undefined;
return avatarMxc;
};
export const useRoomName = (room: Room): string => {
const [name, setName] = useState(room.name);
useEffect(() => {
2026-03-07 18:03:32 +11:00
setName(room.name);
const handleRoomNameChange: RoomEventHandlerMap[RoomEvent.Name] = () => {
setName(room.name);
};
room.on(RoomEvent.Name, handleRoomNameChange);
return () => {
room.removeListener(RoomEvent.Name, handleRoomNameChange);
};
}, [room]);
return name;
};
export const LOCAL_ROOM_NAMES_KEY = 'io.lotus.room_names';
export type LocalRoomNamesContent = { rooms: Record<string, string> };
export function getLocalRoomNamesContent(mx: ReturnType<typeof useMatrixClient>): LocalRoomNamesContent {
// Use any-cast because LOCAL_ROOM_NAMES_KEY is not in matrix-js-sdk AccountDataEvents
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const raw: unknown = (mx as any).getAccountData(LOCAL_ROOM_NAMES_KEY)?.getContent();
if (
raw &&
typeof raw === 'object' &&
'rooms' in raw &&
// eslint-disable-next-line @typescript-eslint/no-explicit-any
typeof (raw as any).rooms === 'object'
) {
return raw as LocalRoomNamesContent;
}
return { rooms: {} };
}
export const useLocalRoomName = (room: Room): string => {
const mx = useMatrixClient();
const getLocalName = useCallback((): string => {
const content = getLocalRoomNamesContent(mx);
return content.rooms[room.roomId] ?? room.name;
}, [mx, room]);
const [name, setName] = useState(getLocalName);
useEffect(() => {
setName(getLocalName());
const handleAccountData = (event: MatrixEvent) => {
if (event.getType() !== LOCAL_ROOM_NAMES_KEY) return;
setName(getLocalName());
};
mx.on(ClientEvent.AccountData, handleAccountData);
const handleRoomNameChange: RoomEventHandlerMap[RoomEvent.Name] = () => {
setName(getLocalName());
};
room.on(RoomEvent.Name, handleRoomNameChange);
return () => {
mx.removeListener(ClientEvent.AccountData, handleAccountData);
room.removeListener(RoomEvent.Name, handleRoomNameChange);
};
}, [mx, room, getLocalName]);
return name;
};
export const useHasLocalRoomName = (roomId: string): boolean => {
const mx = useMatrixClient();
const check = useCallback((): boolean => {
const content = getLocalRoomNamesContent(mx);
return !!content.rooms[roomId];
}, [mx, roomId]);
const [hasLocal, setHasLocal] = useState(check);
useEffect(() => {
setHasLocal(check());
const handleAccountData = (event: MatrixEvent) => {
if (event.getType() !== LOCAL_ROOM_NAMES_KEY) return;
setHasLocal(check());
};
mx.on(ClientEvent.AccountData, handleAccountData);
return () => {
mx.removeListener(ClientEvent.AccountData, handleAccountData);
};
}, [mx, check]);
return hasLocal;
};
export type RoomTopicContent = {
topic: string;
formatted_body?: string;
format?: string;
};
export const useRoomTopic = (room: Room): RoomTopicContent | undefined => {
const topicEvent = useStateEvent(room, StateEvent.RoomTopic);
const content = topicEvent?.getContent();
if (!content || typeof content.topic !== 'string') return undefined;
return {
topic: content.topic,
formatted_body: typeof content.formatted_body === 'string' ? content.formatted_body : undefined,
format: typeof content.format === 'string' ? content.format : undefined,
};
};
export const useRoomJoinRule = (room: Room): RoomJoinRulesEventContent | undefined => {
const mEvent = useStateEvent(room, StateEvent.RoomJoinRules);
const joinRuleContent = mEvent?.getContent<RoomJoinRulesEventContent>();
return joinRuleContent;
};