// Single source of truth for «can the user start a Vojo DM voice call // in this room?». Both `RoomViewHeaderDm`'s phone-icon button and the // `Call` action inside `UserRoomProfile` consult this hook so the two // surfaces can't drift apart — round-7 review caught a bug where the // profile button skipped the bridged-room and bot-control gates and // would have offered to start a Matrix-RTC call inside a // mautrix-telegram puppet DM. // // Four-gate predicate, mirroring the call-lifecycle hooks // (`useIncomingRtcNotifications`, `useCallerAutoHangup`) so the // visibility guard matches the actual deliverability: // • member-count = 2 (true 1:1 — read via `useIsOneOnOne`'s context // so we follow the same reactive source the rest of the app uses) // • `m.direct`-tagged — ring delivery still gates on this // • not a bridged room — MSC2346 `m.bridge` exclusion keeps the // surface hidden in mautrix-telegram puppet DMs (no Matrix-RTC // equivalent) // • not a bot-control room — bot DMs aren't human-callable // // `useIsOneOnOne` is route-context-bound; this hook is therefore only // meaningful for the room currently rendered by `Room.tsx`. Callers // outside that scope must compute their own member-count signal. import { Room } from 'matrix-js-sdk'; import { useAtomValue } from 'jotai'; import { useMatrixClient } from './useMatrixClient'; import { useIsOneOnOne } from './useRoom'; import { useIsBridgedRoom } from './useIsBridgedRoom'; import { useBotPresets } from '../features/bots/catalog'; import { isCatalogBotControlRoom } from '../features/bots/room'; import { mDirectAtom } from '../state/mDirectList'; export const useDmCallVisible = (room: Room): boolean => { const mx = useMatrixClient(); const isOneOnOne = useIsOneOnOne(); const mDirects = useAtomValue(mDirectAtom); const isBridged = useIsBridgedRoom(room); const bots = useBotPresets(); const isBotControlRoom = isCatalogBotControlRoom(mx, room, bots); return isOneOnOne && mDirects.has(room.roomId) && !isBridged && !isBotControlRoom; };