added initial waiting room components and contexts
This commit is contained in:
parent
ceb1bf74ca
commit
0f1187fb08
|
|
@ -1,8 +1,14 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
WaitingRoomModal,
|
||||
WaitingRoomNotification,
|
||||
} from '@dailyjs/shared/components/WaitingRoom';
|
||||
import { useCallState } from '@dailyjs/shared/contexts/CallProvider';
|
||||
import { useMediaDevices } from '@dailyjs/shared/contexts/MediaDeviceProvider';
|
||||
import { useParticipants } from '@dailyjs/shared/contexts/ParticipantsProvider';
|
||||
import { useUIState } from '@dailyjs/shared/contexts/UIStateProvider';
|
||||
import { ReactComponent as IconAdd } from '@dailyjs/shared/icons/add-md.svg';
|
||||
import { useWaitingRoom } from '@dailyjs/shared/contexts/WaitingRoomProvider';
|
||||
|
||||
import { ReactComponent as IconCameraOff } from '@dailyjs/shared/icons/camera-off-md.svg';
|
||||
import { ReactComponent as IconCameraOn } from '@dailyjs/shared/icons/camera-on-md.svg';
|
||||
import { ReactComponent as IconLeave } from '@dailyjs/shared/icons/leave-md.svg';
|
||||
|
|
@ -17,9 +23,11 @@ import { Header } from './Header';
|
|||
import { Tray, TrayButton } from './Tray';
|
||||
|
||||
export const Room = ({ onLeave }) => {
|
||||
const { callObject, addFakeParticipant } = useCallState();
|
||||
const { callObject } = useCallState();
|
||||
const { localParticipant } = useParticipants();
|
||||
const { setShowDeviceModal } = useUIState();
|
||||
const { isCamMuted, isMicMuted } = useMediaDevices();
|
||||
const { setShowModal, showModal } = useWaitingRoom();
|
||||
|
||||
const toggleCamera = (newState) => {
|
||||
if (!callObject) return false;
|
||||
|
|
@ -39,6 +47,16 @@ export const Room = ({ onLeave }) => {
|
|||
<VideoGrid />
|
||||
</main>
|
||||
|
||||
{/* Show waiting room notification & modal if call owner */}
|
||||
{localParticipant?.isOwner && (
|
||||
<>
|
||||
<WaitingRoomNotification />
|
||||
{showModal && (
|
||||
<WaitingRoomModal onClose={() => setShowModal(false)} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
<Tray>
|
||||
<TrayButton
|
||||
label="Camera"
|
||||
|
|
@ -57,10 +75,9 @@ export const Room = ({ onLeave }) => {
|
|||
<TrayButton label="Settings" onClick={() => setShowDeviceModal(true)}>
|
||||
<IconSettings />
|
||||
</TrayButton>
|
||||
<TrayButton label="Add fake" onClick={() => addFakeParticipant()}>
|
||||
<IconAdd />
|
||||
</TrayButton>
|
||||
|
||||
<span className="divider" />
|
||||
|
||||
<TrayButton label="Leave" onClick={onLeave} orange>
|
||||
<IconLeave />
|
||||
</TrayButton>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { MediaDeviceProvider } from '@dailyjs/shared/contexts/MediaDeviceProvide
|
|||
import { ParticipantsProvider } from '@dailyjs/shared/contexts/ParticipantsProvider';
|
||||
import { TracksProvider } from '@dailyjs/shared/contexts/TracksProvider';
|
||||
import { UIStateProvider } from '@dailyjs/shared/contexts/UIStateProvider';
|
||||
import { WaitingRoomProvider } from '@dailyjs/shared/contexts/WaitingRoomProvider';
|
||||
import PropTypes from 'prop-types';
|
||||
import App from '../components/App';
|
||||
import { Intro, NotConfigured } from '../components/Intro';
|
||||
|
|
@ -95,7 +96,9 @@ export default function Index({ domain, isConfigured = false }) {
|
|||
<ParticipantsProvider>
|
||||
<TracksProvider>
|
||||
<MediaDeviceProvider>
|
||||
<App />
|
||||
<WaitingRoomProvider>
|
||||
<App />
|
||||
</WaitingRoomProvider>
|
||||
</MediaDeviceProvider>
|
||||
</TracksProvider>
|
||||
</ParticipantsProvider>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import { useCallState } from '@dailyjs/shared/contexts/CallProvider';
|
||||
|
||||
export const WaitingRoom = () => {
|
||||
const { callObject } = useCallState();
|
||||
|
||||
/**
|
||||
* Show notification when waiting participants change.
|
||||
*/
|
||||
useEffect(() => {
|
||||
const handleWaitingParticipantAdded = () => {
|
||||
console.log('people are waiting');
|
||||
// setShowNotification(Object.keys(daily.waitingParticipants()).length > 0);
|
||||
};
|
||||
|
||||
callObject.on('waiting-participant-added', handleWaitingParticipantAdded);
|
||||
return () => {
|
||||
callObject.off(
|
||||
'waiting-participant-added',
|
||||
handleWaitingParticipantAdded
|
||||
);
|
||||
};
|
||||
}, [callObject]);
|
||||
|
||||
return <div>Waiting Room</div>;
|
||||
};
|
||||
|
||||
export default WaitingRoom;
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import React from 'react';
|
||||
import Modal from '@dailyjs/shared/components/Modal';
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export const WaitingRoomModal = ({ onClose }) => (
|
||||
<Modal title="Waiting room" isOpen onClose={() => onClose()} actions={[]}>
|
||||
Hello
|
||||
</Modal>
|
||||
);
|
||||
|
||||
WaitingRoomModal.propTypes = {
|
||||
onClose: PropTypes.func,
|
||||
};
|
||||
|
||||
export default WaitingRoomModal;
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { useCallState } from '../../contexts/CallProvider';
|
||||
import { useWaitingRoom } from '../../contexts/WaitingRoomProvider';
|
||||
import { Button } from '../Button';
|
||||
|
||||
export const WaitingRoomNotification = () => {
|
||||
const { callObject } = useCallState();
|
||||
const {
|
||||
denyAccess,
|
||||
grantAccess,
|
||||
showModal,
|
||||
setShowModal,
|
||||
waitingParticipants,
|
||||
} = useWaitingRoom();
|
||||
const [showNotification, setShowNotification] = useState(false);
|
||||
|
||||
/**
|
||||
* Show notification when waiting participants change.
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (showModal) return false;
|
||||
|
||||
const handleWaitingParticipantAdded = () => {
|
||||
setShowNotification(
|
||||
Object.keys(callObject.waitingParticipants()).length > 0
|
||||
);
|
||||
};
|
||||
|
||||
callObject.on('waiting-participant-added', handleWaitingParticipantAdded);
|
||||
return () => {
|
||||
callObject.off(
|
||||
'waiting-participant-added',
|
||||
handleWaitingParticipantAdded
|
||||
);
|
||||
};
|
||||
}, [callObject, showModal]);
|
||||
|
||||
/**
|
||||
* Hide notification when people panel is opened.
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (showModal) setShowNotification(false);
|
||||
}, [showModal]);
|
||||
|
||||
if (!showNotification || waitingParticipants.length === 0) return null;
|
||||
|
||||
const hasMultiplePeopleWaiting = waitingParticipants.length > 1;
|
||||
|
||||
const handleViewAllClick = () => {
|
||||
setShowModal(true);
|
||||
setShowNotification(false);
|
||||
};
|
||||
const handleAllowClick = () => {
|
||||
grantAccess(waitingParticipants[0].id);
|
||||
};
|
||||
const handleDenyClick = () => {
|
||||
denyAccess(hasMultiplePeopleWaiting ? 'all' : waitingParticipants[0].id);
|
||||
};
|
||||
const handleClose = () => setShowNotification(false);
|
||||
|
||||
return (
|
||||
<div className="waiting-room-notification">
|
||||
<>
|
||||
{hasMultiplePeopleWaiting ? (
|
||||
<Button onClick={handleViewAllClick}>View all</Button>
|
||||
) : (
|
||||
<Button onClick={handleAllowClick}>Allow</Button>
|
||||
)}
|
||||
<Button onClick={handleDenyClick} variant="secondary">
|
||||
{hasMultiplePeopleWaiting
|
||||
? 'waitingRoom.denyAll'
|
||||
: 'waitingRoom.deny'}
|
||||
</Button>
|
||||
<Button onClick={handleClose} variant="ghost">
|
||||
Close
|
||||
</Button>
|
||||
</>
|
||||
|
||||
<style jsx>{`
|
||||
.waiting-room-notification {
|
||||
position: absolute;
|
||||
right: var(--spacing-sm);
|
||||
top: var(--spacing-sm);
|
||||
background: red;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default WaitingRoomNotification;
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
export { WaitingRoom as default } from './WaitingRoom';
|
||||
export { WaitingRoom } from './WaitingRoom';
|
||||
export { WaitingRoomModal } from './WaitingRoomModal';
|
||||
export { WaitingRoomNotification } from './WaitingRoomNotification';
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
import React, {
|
||||
createContext,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useCallState } from './CallProvider';
|
||||
|
||||
const WaitingRoomContext = createContext(null);
|
||||
|
||||
export const WaitingRoomProvider = ({ children }) => {
|
||||
const { callObject } = useCallState();
|
||||
const [waitingParticipants, setWaitingParticipants] = useState([]);
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
|
||||
const handleWaitingParticipantEvent = useCallback(() => {
|
||||
if (!callObject) return;
|
||||
|
||||
const waiting = Object.entries(callObject.waitingParticipants());
|
||||
|
||||
console.log(`🚪 ${waiting.length} participant(s) waiting for access`);
|
||||
|
||||
setWaitingParticipants((wp) =>
|
||||
waiting.map(([pid, p]) => {
|
||||
const prevWP = wp.find(({ id }) => id === pid);
|
||||
return {
|
||||
...p,
|
||||
joinDate: prevWP?.joinDate ?? new Date(),
|
||||
};
|
||||
})
|
||||
);
|
||||
}, [callObject]);
|
||||
|
||||
useEffect(() => {
|
||||
if (waitingParticipants.length === 0) {
|
||||
setShowModal(false);
|
||||
}
|
||||
}, [waitingParticipants]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!callObject) return false;
|
||||
|
||||
console.log('🚪 Waiting room provider listening for requests');
|
||||
|
||||
const events = [
|
||||
'waiting-participant-added',
|
||||
'waiting-participant-updated',
|
||||
'waiting-participant-removed',
|
||||
];
|
||||
|
||||
events.forEach((e) => callObject.on(e, handleWaitingParticipantEvent));
|
||||
|
||||
return () =>
|
||||
events.forEach((e) => callObject.off(e, handleWaitingParticipantEvent));
|
||||
}, [callObject, handleWaitingParticipantEvent]);
|
||||
|
||||
const updateWaitingParticipant = (id, grantRequestedAccess) => {
|
||||
if (!waitingParticipants.some((p) => p.id === id)) return;
|
||||
callObject.updateWaitingParticipant(id, {
|
||||
grantRequestedAccess,
|
||||
});
|
||||
setWaitingParticipants((wp) => wp.filter((p) => p.id !== id));
|
||||
};
|
||||
|
||||
const updateAllWaitingParticipants = (grantRequestedAccess) => {
|
||||
if (!waitingParticipants.length) return;
|
||||
callObject.updateWaitingParticipants({
|
||||
'*': {
|
||||
grantRequestedAccess,
|
||||
},
|
||||
});
|
||||
setWaitingParticipants([]);
|
||||
};
|
||||
|
||||
const grantAccess = (id = 'all') => {
|
||||
if (id === 'all') {
|
||||
updateAllWaitingParticipants(true);
|
||||
return;
|
||||
}
|
||||
updateWaitingParticipant(id, true);
|
||||
};
|
||||
const denyAccess = (id = 'all') => {
|
||||
if (id === 'all') {
|
||||
updateAllWaitingParticipants(false);
|
||||
return;
|
||||
}
|
||||
updateWaitingParticipant(id, false);
|
||||
};
|
||||
|
||||
return (
|
||||
<WaitingRoomContext.Provider
|
||||
value={{
|
||||
denyAccess,
|
||||
grantAccess,
|
||||
setShowModal,
|
||||
showModal,
|
||||
waitingParticipants,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</WaitingRoomContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
WaitingRoomProvider.propTypes = {
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
export const useWaitingRoom = () => useContext(WaitingRoomContext);
|
||||
Loading…
Reference in New Issue