snapshot of https://github.com/RocketChat/Rocket.Chat.git (develop, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
import type { IRoom } from '@rocket.chat/core-typings';
|
||||
import { Skeleton } from '@rocket.chat/fuselage';
|
||||
import { useStableCallback } from '@rocket.chat/fuselage-hooks';
|
||||
import { useEndpoint } from '@rocket.chat/ui-contexts';
|
||||
import {
|
||||
useVideoConfSetPreferences,
|
||||
VideoConfPopup,
|
||||
VideoConfPopupContent,
|
||||
VideoConfPopupControllers,
|
||||
VideoConfController,
|
||||
useVideoConfControllers,
|
||||
VideoConfButton,
|
||||
VideoConfPopupFooter,
|
||||
VideoConfPopupFooterButtons,
|
||||
VideoConfPopupTitle,
|
||||
VideoConfPopupHeader,
|
||||
} from '@rocket.chat/ui-video-conf';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import VideoConfPopupRoomInfo from './VideoConfPopupRoomInfo';
|
||||
import { useVideoConfRoomName } from '../../hooks/useVideoConfRoomName';
|
||||
|
||||
export type IncomingPopupProps = {
|
||||
id: string;
|
||||
room: IRoom;
|
||||
position: number;
|
||||
onClose: (id: string) => void;
|
||||
onMute: (id: string) => void;
|
||||
onConfirm: () => void;
|
||||
};
|
||||
|
||||
const IncomingPopup = ({ id, room, position, onClose, onMute, onConfirm }: IncomingPopupProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { controllersConfig, handleToggleMic, handleToggleCam } = useVideoConfControllers();
|
||||
const setPreferences = useVideoConfSetPreferences();
|
||||
const roomName = useVideoConfRoomName(room);
|
||||
|
||||
const videoConfInfo = useEndpoint('GET', '/v1/video-conference.info');
|
||||
const { data, isPending, isSuccess } = useQuery({
|
||||
queryKey: ['getVideoConferenceInfo', id],
|
||||
queryFn: async () => videoConfInfo({ callId: id }),
|
||||
});
|
||||
|
||||
const showMic = Boolean(data?.capabilities?.mic);
|
||||
const showCam = Boolean(data?.capabilities?.cam);
|
||||
|
||||
const handleJoinCall = useStableCallback(() => {
|
||||
setPreferences(controllersConfig);
|
||||
onConfirm();
|
||||
});
|
||||
|
||||
return (
|
||||
<VideoConfPopup position={position} id={id} aria-label={t('Incoming_call_from__roomName__', { roomName })}>
|
||||
<VideoConfPopupHeader>
|
||||
<VideoConfPopupTitle text={t('Incoming_call_from')} />
|
||||
{isPending && <Skeleton />}
|
||||
{isSuccess && (showMic || showCam) && (
|
||||
<VideoConfPopupControllers>
|
||||
{showCam && (
|
||||
<VideoConfController
|
||||
active={controllersConfig.cam}
|
||||
title={controllersConfig.cam ? t('Cam_on') : t('Cam_off')}
|
||||
icon={controllersConfig.cam ? 'video' : 'video-off'}
|
||||
onClick={handleToggleCam}
|
||||
/>
|
||||
)}
|
||||
{showMic && (
|
||||
<VideoConfController
|
||||
active={controllersConfig.mic}
|
||||
title={controllersConfig.mic ? t('Mic_on') : t('Mic_off')}
|
||||
icon={controllersConfig.mic ? 'mic' : 'mic-off'}
|
||||
onClick={handleToggleMic}
|
||||
/>
|
||||
)}
|
||||
</VideoConfPopupControllers>
|
||||
)}
|
||||
</VideoConfPopupHeader>
|
||||
<VideoConfPopupContent>
|
||||
<VideoConfPopupRoomInfo room={room} />
|
||||
</VideoConfPopupContent>
|
||||
<VideoConfPopupFooter>
|
||||
<VideoConfPopupFooterButtons>
|
||||
<VideoConfButton primary onClick={handleJoinCall}>
|
||||
{t('Accept')}
|
||||
</VideoConfButton>
|
||||
{onClose && (
|
||||
<VideoConfButton danger secondary onClick={(): void => onClose(id)}>
|
||||
{t('Decline')}
|
||||
</VideoConfButton>
|
||||
)}
|
||||
<VideoConfController small={false} secondary title={t('Mute_and_dismiss')} icon='cross' onClick={(): void => onMute(id)} />
|
||||
</VideoConfPopupFooterButtons>
|
||||
</VideoConfPopupFooter>
|
||||
</VideoConfPopup>
|
||||
);
|
||||
};
|
||||
|
||||
export default IncomingPopup;
|
||||
@@ -0,0 +1,74 @@
|
||||
import type { IRoom } from '@rocket.chat/core-typings';
|
||||
import {
|
||||
VideoConfPopup,
|
||||
VideoConfPopupContent,
|
||||
VideoConfPopupControllers,
|
||||
VideoConfController,
|
||||
useVideoConfControllers,
|
||||
VideoConfButton,
|
||||
VideoConfPopupFooter,
|
||||
VideoConfPopupFooterButtons,
|
||||
VideoConfPopupTitle,
|
||||
VideoConfPopupHeader,
|
||||
useVideoConfCapabilities,
|
||||
useVideoConfPreferences,
|
||||
} from '@rocket.chat/ui-video-conf';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import VideoConfPopupRoomInfo from './VideoConfPopupRoomInfo';
|
||||
import { useVideoConfRoomName } from '../../hooks/useVideoConfRoomName';
|
||||
|
||||
export type OutgoingPopupProps = {
|
||||
id: string;
|
||||
room: IRoom;
|
||||
onClose: (id: string) => void;
|
||||
};
|
||||
|
||||
const OutgoingPopup = ({ room, onClose, id }: OutgoingPopupProps) => {
|
||||
const { t } = useTranslation();
|
||||
const videoConfPreferences = useVideoConfPreferences();
|
||||
const { controllersConfig } = useVideoConfControllers(videoConfPreferences);
|
||||
const capabilities = useVideoConfCapabilities();
|
||||
const roomName = useVideoConfRoomName(room);
|
||||
|
||||
const showCam = !!capabilities.cam;
|
||||
const showMic = !!capabilities.mic;
|
||||
|
||||
return (
|
||||
<VideoConfPopup aria-label={t('Calling__roomName__', { roomName })}>
|
||||
<VideoConfPopupHeader>
|
||||
<VideoConfPopupTitle text={t('Calling')} counter />
|
||||
{(showCam || showMic) && (
|
||||
<VideoConfPopupControllers>
|
||||
{showCam && (
|
||||
<VideoConfController
|
||||
active={controllersConfig.cam}
|
||||
title={controllersConfig.cam ? t('Cam_on') : t('Cam_off')}
|
||||
icon={controllersConfig.cam ? 'video' : 'video-off'}
|
||||
disabled
|
||||
/>
|
||||
)}
|
||||
{showMic && (
|
||||
<VideoConfController
|
||||
active={controllersConfig.mic}
|
||||
title={controllersConfig.mic ? t('Mic_on') : t('Mic_off')}
|
||||
icon={controllersConfig.mic ? 'mic' : 'mic-off'}
|
||||
disabled
|
||||
/>
|
||||
)}
|
||||
</VideoConfPopupControllers>
|
||||
)}
|
||||
</VideoConfPopupHeader>
|
||||
<VideoConfPopupContent>
|
||||
<VideoConfPopupRoomInfo room={room} />
|
||||
</VideoConfPopupContent>
|
||||
<VideoConfPopupFooter>
|
||||
<VideoConfPopupFooterButtons>
|
||||
{onClose && <VideoConfButton onClick={(): void => onClose(id)}>{t('Cancel')}</VideoConfButton>}
|
||||
</VideoConfPopupFooterButtons>
|
||||
</VideoConfPopupFooter>
|
||||
</VideoConfPopup>
|
||||
);
|
||||
};
|
||||
|
||||
export default OutgoingPopup;
|
||||
@@ -0,0 +1,109 @@
|
||||
import type { IRoom } from '@rocket.chat/core-typings';
|
||||
import { useOutsideClick, useStableCallback } from '@rocket.chat/fuselage-hooks';
|
||||
import {
|
||||
VideoConfPopup,
|
||||
VideoConfPopupHeader,
|
||||
VideoConfPopupContent,
|
||||
VideoConfPopupControllers,
|
||||
VideoConfController,
|
||||
useVideoConfControllers,
|
||||
VideoConfButton,
|
||||
VideoConfPopupFooter,
|
||||
VideoConfPopupTitle,
|
||||
VideoConfPopupFooterButtons,
|
||||
useVideoConfSetPreferences,
|
||||
useVideoConfCapabilities,
|
||||
useVideoConfPreferences,
|
||||
} from '@rocket.chat/ui-video-conf';
|
||||
import { useCallback, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import VideoConfPopupRoomInfo from './VideoConfPopupRoomInfo';
|
||||
import { useVideoConfRoomName } from '../../hooks/useVideoConfRoomName';
|
||||
|
||||
export type StartCallPopupProps = {
|
||||
id: string;
|
||||
loading: boolean;
|
||||
room: IRoom;
|
||||
onClose: () => void;
|
||||
onConfirm: () => void;
|
||||
};
|
||||
|
||||
const StartCallPopup = ({ id, loading, room, onClose, onConfirm }: StartCallPopupProps) => {
|
||||
const { t } = useTranslation();
|
||||
const ref = useRef<HTMLElement | null>(null);
|
||||
useOutsideClick([ref], !loading ? onClose : () => undefined);
|
||||
|
||||
const setPreferences = useVideoConfSetPreferences();
|
||||
const videoConfPreferences = useVideoConfPreferences();
|
||||
const { controllersConfig, handleToggleMic, handleToggleCam } = useVideoConfControllers(videoConfPreferences);
|
||||
const capabilities = useVideoConfCapabilities();
|
||||
const roomName = useVideoConfRoomName(room);
|
||||
|
||||
const dialogLabel =
|
||||
room.t === 'd' ? `${t('Start_a_call_with__roomName__', { roomName })}` : `${t('Start_a_call_in__roomName__', { roomName })}`;
|
||||
|
||||
const showCam = !!capabilities.cam;
|
||||
const showMic = !!capabilities.mic;
|
||||
|
||||
const handleStartCall = useStableCallback(() => {
|
||||
setPreferences(controllersConfig);
|
||||
onConfirm();
|
||||
});
|
||||
|
||||
const callbackRef = useCallback(
|
||||
(node: HTMLElement | null) => {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
ref.current = node;
|
||||
node.addEventListener('keydown', (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') {
|
||||
onClose();
|
||||
}
|
||||
});
|
||||
},
|
||||
[onClose],
|
||||
);
|
||||
|
||||
return (
|
||||
<VideoConfPopup ref={callbackRef} id={id} aria-label={dialogLabel}>
|
||||
<VideoConfPopupHeader>
|
||||
<VideoConfPopupTitle text={t('Start_a_call')} />
|
||||
{(showCam || showMic) && (
|
||||
<VideoConfPopupControllers>
|
||||
{showCam && (
|
||||
<VideoConfController
|
||||
active={controllersConfig.cam}
|
||||
title={controllersConfig.cam ? t('Cam_on') : t('Cam_off')}
|
||||
icon={controllersConfig.cam ? 'video' : 'video-off'}
|
||||
onClick={handleToggleCam}
|
||||
/>
|
||||
)}
|
||||
{showMic && (
|
||||
<VideoConfController
|
||||
active={controllersConfig.mic}
|
||||
title={controllersConfig.mic ? t('Mic_on') : t('Mic_off')}
|
||||
icon={controllersConfig.mic ? 'mic' : 'mic-off'}
|
||||
onClick={handleToggleMic}
|
||||
/>
|
||||
)}
|
||||
</VideoConfPopupControllers>
|
||||
)}
|
||||
</VideoConfPopupHeader>
|
||||
<VideoConfPopupContent>
|
||||
<VideoConfPopupRoomInfo room={room} />
|
||||
</VideoConfPopupContent>
|
||||
<VideoConfPopupFooter>
|
||||
<VideoConfPopupFooterButtons>
|
||||
<VideoConfButton disabled={loading} primary onClick={handleStartCall}>
|
||||
{t('Start_call')}
|
||||
</VideoConfButton>
|
||||
</VideoConfPopupFooterButtons>
|
||||
</VideoConfPopupFooter>
|
||||
</VideoConfPopup>
|
||||
);
|
||||
};
|
||||
|
||||
export default StartCallPopup;
|
||||
@@ -0,0 +1,79 @@
|
||||
import { useFocusManager } from '@react-aria/focus';
|
||||
import type { IRoom } from '@rocket.chat/core-typings';
|
||||
import { useUserRoom } from '@rocket.chat/ui-contexts';
|
||||
import {
|
||||
useVideoConfAcceptCall,
|
||||
useVideoConfAbortCall,
|
||||
useVideoConfRejectIncomingCall,
|
||||
useVideoConfDismissCall,
|
||||
useVideoConfStartCall,
|
||||
useVideoConfDismissOutgoing,
|
||||
} from '@rocket.chat/ui-video-conf';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import IncomingPopup from './IncomingPopup';
|
||||
import OutgoingPopup from './OutgoingPopup';
|
||||
import StartCallPopup from './StartCallPopup';
|
||||
|
||||
export type TimedVideoConfPopupProps = {
|
||||
id: string;
|
||||
rid: IRoom['_id'];
|
||||
isReceiving?: boolean;
|
||||
isCalling?: boolean;
|
||||
position: number;
|
||||
onClose?: (id: string) => void;
|
||||
};
|
||||
|
||||
const TimedVideoConfPopup = ({ id, rid, isReceiving = false, isCalling = false, position }: TimedVideoConfPopupProps) => {
|
||||
const [starting, setStarting] = useState(false);
|
||||
const acceptCall = useVideoConfAcceptCall();
|
||||
const abortCall = useVideoConfAbortCall();
|
||||
const rejectCall = useVideoConfRejectIncomingCall();
|
||||
const dismissCall = useVideoConfDismissCall();
|
||||
const startCall = useVideoConfStartCall();
|
||||
const dismissOutgoing = useVideoConfDismissOutgoing();
|
||||
const focusManager = useFocusManager();
|
||||
const room = useUserRoom(rid);
|
||||
|
||||
useEffect(() => {
|
||||
focusManager?.focusFirst();
|
||||
}, [focusManager]);
|
||||
|
||||
if (!room) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleConfirm = (): void => {
|
||||
acceptCall(id);
|
||||
};
|
||||
|
||||
const handleClose = (id: string): void => {
|
||||
if (isReceiving) {
|
||||
rejectCall(id);
|
||||
return;
|
||||
}
|
||||
|
||||
abortCall();
|
||||
};
|
||||
|
||||
const handleMute = (): void => {
|
||||
dismissCall(id);
|
||||
};
|
||||
|
||||
const handleStartCall = async (): Promise<void> => {
|
||||
setStarting(true);
|
||||
startCall(rid);
|
||||
};
|
||||
|
||||
if (isReceiving) {
|
||||
return <IncomingPopup room={room} id={id} position={position} onClose={handleClose} onMute={handleMute} onConfirm={handleConfirm} />;
|
||||
}
|
||||
|
||||
if (isCalling) {
|
||||
return <OutgoingPopup room={room} id={id} onClose={handleClose} />;
|
||||
}
|
||||
|
||||
return <StartCallPopup loading={starting} room={room} id={id} onClose={dismissOutgoing} onConfirm={handleStartCall} />;
|
||||
};
|
||||
|
||||
export default TimedVideoConfPopup;
|
||||
@@ -0,0 +1,39 @@
|
||||
import type { IRoom } from '@rocket.chat/core-typings';
|
||||
import { isDirectMessageRoom, isMultipleDirectMessageRoom } from '@rocket.chat/core-typings';
|
||||
import { RoomAvatar } from '@rocket.chat/ui-avatar';
|
||||
import { useUser } from '@rocket.chat/ui-contexts';
|
||||
import { VideoConfPopupInfo } from '@rocket.chat/ui-video-conf';
|
||||
|
||||
import { RoomIcon } from '../../../../../../components/RoomIcon';
|
||||
import ReactiveUserStatus from '../../../../../../components/UserStatus/ReactiveUserStatus';
|
||||
import { useVideoConfRoomName } from '../../hooks/useVideoConfRoomName';
|
||||
|
||||
export type VideoConfPopupRoomInfoProps = { room: IRoom };
|
||||
|
||||
const VideoConfPopupRoomInfo = ({ room }: VideoConfPopupRoomInfoProps) => {
|
||||
const ownUser = useUser();
|
||||
const [userId] = room?.uids?.filter((uid) => uid !== ownUser?._id) || [];
|
||||
const roomName = useVideoConfRoomName(room);
|
||||
const avatar = <RoomAvatar room={room} size='x40' />;
|
||||
|
||||
if (isDirectMessageRoom(room)) {
|
||||
return (
|
||||
<VideoConfPopupInfo
|
||||
avatar={avatar}
|
||||
{...(userId && {
|
||||
icon: isMultipleDirectMessageRoom(room) ? <RoomIcon placement='default' room={room} /> : <ReactiveUserStatus uid={userId} />,
|
||||
})}
|
||||
>
|
||||
{roomName}
|
||||
</VideoConfPopupInfo>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<VideoConfPopupInfo avatar={avatar} icon={<RoomIcon placement='default' room={room} />}>
|
||||
{roomName}
|
||||
</VideoConfPopupInfo>
|
||||
);
|
||||
};
|
||||
|
||||
export default VideoConfPopupRoomInfo;
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from './TimedVideoConfPopup';
|
||||
@@ -0,0 +1,22 @@
|
||||
import { mockAppRoot } from '@rocket.chat/mock-providers';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
|
||||
import VideoConfPopups from './VideoConfPopups';
|
||||
import { createFakeRoom } from '../../../../../../tests/mocks/data';
|
||||
import { createFakeVideoConfCall, createFakeIncomingCall } from '../../../../../../tests/mocks/utils/video-conference';
|
||||
|
||||
const fakeRoom = createFakeRoom({ t: 'd' });
|
||||
const fakeDirectVideoConfCall = createFakeVideoConfCall({ type: 'direct', rid: fakeRoom._id });
|
||||
const fakeIncomingCall = createFakeIncomingCall({ rid: fakeRoom._id });
|
||||
|
||||
test('should render video conference incoming popup', async () => {
|
||||
render(<VideoConfPopups />, {
|
||||
wrapper: mockAppRoot()
|
||||
.withRoom(fakeRoom)
|
||||
.withEndpoint('GET', '/v1/video-conference.info', () => fakeDirectVideoConfCall as any)
|
||||
.withIncomingCalls([fakeIncomingCall])
|
||||
.build(),
|
||||
});
|
||||
|
||||
expect(await screen.findByRole('dialog')).toBeInTheDocument();
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
import { FocusScope } from '@react-aria/focus';
|
||||
import { useCustomSound } from '@rocket.chat/ui-contexts';
|
||||
import type { VideoConfPopupPayload } from '@rocket.chat/ui-video-conf';
|
||||
import {
|
||||
VideoConfPopupBackdrop,
|
||||
useVideoConfIsCalling,
|
||||
useVideoConfIsRinging,
|
||||
useVideoConfIncomingCalls,
|
||||
VideoConfPopupSkeleton,
|
||||
} from '@rocket.chat/ui-video-conf';
|
||||
import { lazy, Suspense, useEffect, useMemo } from 'react';
|
||||
|
||||
import VideoConfPopupPortal from '../../../../../portals/VideoConfPopupPortal';
|
||||
|
||||
const VideoConfPopup = lazy(() => import('./VideoConfPopup'));
|
||||
|
||||
export type VideoConfPopupsProps = { children?: VideoConfPopupPayload };
|
||||
|
||||
const VideoConfPopups = ({ children }: VideoConfPopupsProps) => {
|
||||
const { callSounds } = useCustomSound();
|
||||
const incomingCalls = useVideoConfIncomingCalls();
|
||||
const isRinging = useVideoConfIsRinging();
|
||||
const isCalling = useVideoConfIsCalling();
|
||||
|
||||
const popups = useMemo(
|
||||
() =>
|
||||
incomingCalls
|
||||
.filter((incomingCall) => !incomingCall.dismissed)
|
||||
.map((incomingCall) => ({ id: incomingCall.callId, rid: incomingCall.rid, isReceiving: true })),
|
||||
[incomingCalls],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isRinging) {
|
||||
callSounds.playRinger();
|
||||
}
|
||||
|
||||
if (isCalling) {
|
||||
callSounds.playDialer();
|
||||
}
|
||||
|
||||
return (): void => {
|
||||
callSounds.stopRinger();
|
||||
callSounds.stopDialer();
|
||||
};
|
||||
}, [isRinging, isCalling, callSounds]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{(children || popups?.length > 0) && (
|
||||
<VideoConfPopupPortal>
|
||||
{(children ? [children, ...popups] : popups).map(({ id, rid, isReceiving }, index = 1) => (
|
||||
<VideoConfPopupBackdrop key={id}>
|
||||
<Suspense fallback={<VideoConfPopupSkeleton />}>
|
||||
<FocusScope restoreFocus>
|
||||
<VideoConfPopup id={id} rid={rid} isReceiving={isReceiving} isCalling={isCalling} position={index * 10} />
|
||||
</FocusScope>
|
||||
</Suspense>
|
||||
</VideoConfPopupBackdrop>
|
||||
))}
|
||||
</VideoConfPopupPortal>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default VideoConfPopups;
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from './VideoConfPopups';
|
||||
Reference in New Issue
Block a user