{
setShowDeviceModal(true)}>
- addFakeParticipant()}>
-
-
+
+
diff --git a/dailyjs/basic-call/pages/index.js b/dailyjs/basic-call/pages/index.js
index 3f0250e..b55c5ce 100644
--- a/dailyjs/basic-call/pages/index.js
+++ b/dailyjs/basic-call/pages/index.js
@@ -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 }) {
-
+
+
+
diff --git a/dailyjs/shared/components/WaitingRoom/WaitingRoom.js b/dailyjs/shared/components/WaitingRoom/WaitingRoom.js
new file mode 100644
index 0000000..5452545
--- /dev/null
+++ b/dailyjs/shared/components/WaitingRoom/WaitingRoom.js
@@ -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 Waiting Room
;
+};
+
+export default WaitingRoom;
diff --git a/dailyjs/shared/components/WaitingRoom/WaitingRoomModal.js b/dailyjs/shared/components/WaitingRoom/WaitingRoomModal.js
new file mode 100644
index 0000000..6873d9d
--- /dev/null
+++ b/dailyjs/shared/components/WaitingRoom/WaitingRoomModal.js
@@ -0,0 +1,16 @@
+import React from 'react';
+import Modal from '@dailyjs/shared/components/Modal';
+
+import PropTypes from 'prop-types';
+
+export const WaitingRoomModal = ({ onClose }) => (
+ onClose()} actions={[]}>
+ Hello
+
+);
+
+WaitingRoomModal.propTypes = {
+ onClose: PropTypes.func,
+};
+
+export default WaitingRoomModal;
diff --git a/dailyjs/shared/components/WaitingRoom/WaitingRoomNotification.js b/dailyjs/shared/components/WaitingRoom/WaitingRoomNotification.js
new file mode 100644
index 0000000..06e8688
--- /dev/null
+++ b/dailyjs/shared/components/WaitingRoom/WaitingRoomNotification.js
@@ -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 (
+
+ <>
+ {hasMultiplePeopleWaiting ? (
+
+ ) : (
+
+ )}
+
+
+ >
+
+
+
+ );
+};
+
+export default WaitingRoomNotification;
diff --git a/dailyjs/shared/components/WaitingRoom/index.js b/dailyjs/shared/components/WaitingRoom/index.js
new file mode 100644
index 0000000..d7affb2
--- /dev/null
+++ b/dailyjs/shared/components/WaitingRoom/index.js
@@ -0,0 +1,4 @@
+export { WaitingRoom as default } from './WaitingRoom';
+export { WaitingRoom } from './WaitingRoom';
+export { WaitingRoomModal } from './WaitingRoomModal';
+export { WaitingRoomNotification } from './WaitingRoomNotification';
diff --git a/dailyjs/shared/contexts/WaitingRoomProvider.js b/dailyjs/shared/contexts/WaitingRoomProvider.js
new file mode 100644
index 0000000..978036a
--- /dev/null
+++ b/dailyjs/shared/contexts/WaitingRoomProvider.js
@@ -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 (
+
+ {children}
+
+ );
+};
+
+WaitingRoomProvider.propTypes = {
+ children: PropTypes.node,
+};
+
+export const useWaitingRoom = () => useContext(WaitingRoomContext);