abstracted tray and added ability to pass custom component

This commit is contained in:
J Taylor 2021-06-22 14:02:47 +01:00
parent 9b79d2a510
commit dadd8c6d2b
11 changed files with 111 additions and 70 deletions

View File

@ -8,11 +8,11 @@ import { Asides } from './Asides';
import { Modals } from './Modals'; import { Modals } from './Modals';
export const App = () => { export const App = () => {
const { state, leave } = useCallState(); const { state } = useCallState();
const componentForState = useCallUI({ const componentForState = useCallUI({
state, state,
room: () => <Room onLeave={() => leave()} />, room: () => <Room />,
}); });
// Memoize children to avoid unnecassary renders from HOC // Memoize children to avoid unnecassary renders from HOC

View File

@ -1,48 +1,23 @@
import React from 'react'; import React from 'react';
import { Audio } from '@dailyjs/shared/components/Audio'; import { Audio } from '@dailyjs/shared/components/Audio';
import { Tray, TrayButton } from '@dailyjs/shared/components/Tray'; import { BasicTray } from '@dailyjs/shared/components/Tray';
import { import {
WaitingRoomModal, WaitingRoomModal,
WaitingRoomNotification, WaitingRoomNotification,
} from '@dailyjs/shared/components/WaitingRoom'; } 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 { useParticipants } from '@dailyjs/shared/contexts/ParticipantsProvider';
import { useUIState } from '@dailyjs/shared/contexts/UIStateProvider';
import { useWaitingRoom } from '@dailyjs/shared/contexts/WaitingRoomProvider'; import { useWaitingRoom } from '@dailyjs/shared/contexts/WaitingRoomProvider';
import useJoinSound from '@dailyjs/shared/hooks/useJoinSound'; import useJoinSound from '@dailyjs/shared/hooks/useJoinSound';
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';
import { ReactComponent as IconMicOff } from '@dailyjs/shared/icons/mic-off-md.svg';
import { ReactComponent as IconMicOn } from '@dailyjs/shared/icons/mic-on-md.svg';
import { ReactComponent as IconPeople } from '@dailyjs/shared/icons/people-md.svg';
import { ReactComponent as IconSettings } from '@dailyjs/shared/icons/settings-md.svg';
import PropTypes from 'prop-types';
import { PEOPLE_ASIDE } from '../../../shared/components/Aside/PeopleAside';
import { VideoGrid } from '../VideoGrid'; import { VideoGrid } from '../VideoGrid';
import { Header } from './Header'; import { Header } from './Header';
export const Room = ({ onLeave }) => { export const Room = () => {
const { callObject } = useCallState();
const { setShowDeviceModal, setShowAside } = useUIState();
const { isCamMuted, isMicMuted } = useMediaDevices();
const { setShowModal, showModal } = useWaitingRoom(); const { setShowModal, showModal } = useWaitingRoom();
const { localParticipant } = useParticipants(); const { localParticipant } = useParticipants();
useJoinSound(); useJoinSound();
const toggleCamera = (newState) => {
if (!callObject) return false;
return callObject.setLocalVideo(newState);
};
const toggleMic = (newState) => {
if (!callObject) return false;
return callObject.setLocalAudio(newState);
};
return ( return (
<div className="room"> <div className="room">
<Header /> <Header />
@ -61,39 +36,7 @@ export const Room = ({ onLeave }) => {
</> </>
)} )}
<Tray> <BasicTray />
<TrayButton
label="Camera"
onClick={() => toggleCamera(isCamMuted)}
orange={isCamMuted}
>
{isCamMuted ? <IconCameraOff /> : <IconCameraOn />}
</TrayButton>
<TrayButton
label="Mic"
onClick={() => toggleMic(isMicMuted)}
orange={isMicMuted}
>
{isMicMuted ? <IconMicOff /> : <IconMicOn />}
</TrayButton>
<TrayButton label="Settings" onClick={() => setShowDeviceModal(true)}>
<IconSettings />
</TrayButton>
<TrayButton
label="People"
onClick={() => setShowAside((p) => (p ? null : PEOPLE_ASIDE))}
>
<IconPeople />
</TrayButton>
<span className="divider" />
<TrayButton label="Leave" onClick={onLeave} orange>
<IconLeave />
</TrayButton>
</Tray>
<Audio /> <Audio />
<style jsx>{` <style jsx>{`
@ -118,8 +61,4 @@ export const Room = ({ onLeave }) => {
); );
}; };
Room.propTypes = {
onLeave: PropTypes.func.isRequired,
};
export default Room; export default Room;

View File

@ -12,7 +12,11 @@ function App({ Component, pageProps }) {
</Head> </Head>
<GlobalHead /> <GlobalHead />
<GlobalStyle /> <GlobalStyle />
<Component asides={App.asides} {...pageProps} /> <Component
asides={App.asides}
customTrayComponent={App.customTrayComponent}
{...pageProps}
/>
</> </>
); );
} }
@ -28,5 +32,6 @@ App.propTypes = {
}; };
App.asides = []; App.asides = [];
App.customTrayComponent = null;
export default App; export default App;

View File

@ -17,7 +17,12 @@ import { Intro, NotConfigured } from '../components/Intro';
* - Set call owner status * - Set call owner status
* - Finally, renders the main application loop * - Finally, renders the main application loop
*/ */
export default function Index({ domain, isConfigured = false, asides }) { export default function Index({
domain,
isConfigured = false,
asides,
customTrayComponent,
}) {
const [roomName, setRoomName] = useState(''); const [roomName, setRoomName] = useState('');
const [fetchingToken, setFetchingToken] = useState(false); const [fetchingToken, setFetchingToken] = useState(false);
const [token, setToken] = useState(); const [token, setToken] = useState();
@ -92,7 +97,7 @@ export default function Index({ domain, isConfigured = false, asides }) {
* Main call UI * Main call UI
*/ */
return ( return (
<UIStateProvider asides={asides}> <UIStateProvider asides={asides} customTrayComponent={customTrayComponent}>
<CallProvider domain={domain} room={roomName} token={token}> <CallProvider domain={domain} room={roomName} token={token}>
<ParticipantsProvider> <ParticipantsProvider>
<TracksProvider> <TracksProvider>
@ -112,6 +117,7 @@ Index.propTypes = {
isConfigured: PropTypes.bool.isRequired, isConfigured: PropTypes.bool.isRequired,
domain: PropTypes.string, domain: PropTypes.string,
asides: PropTypes.arrayOf(PropTypes.func), asides: PropTypes.arrayOf(PropTypes.func),
customTrayComponent: PropTypes.node,
}; };
export async function getStaticProps() { export async function getStaticProps() {

View File

@ -0,0 +1,68 @@
import React from 'react';
import { PEOPLE_ASIDE } from '@dailyjs/shared/components/Aside/PeopleAside';
import { useCallState } from '@dailyjs/shared/contexts/CallProvider';
import { useMediaDevices } from '@dailyjs/shared/contexts/MediaDeviceProvider';
import { useUIState } from '@dailyjs/shared/contexts/UIStateProvider';
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';
import { ReactComponent as IconMicOff } from '@dailyjs/shared/icons/mic-off-md.svg';
import { ReactComponent as IconMicOn } from '@dailyjs/shared/icons/mic-on-md.svg';
import { ReactComponent as IconPeople } from '@dailyjs/shared/icons/people-md.svg';
import { ReactComponent as IconSettings } from '@dailyjs/shared/icons/settings-md.svg';
import { Tray, TrayButton } from './Tray';
export const BasicTray = () => {
const { callObject, leave } = useCallState();
const { customTrayComponent, setShowDeviceModal, setShowAside } =
useUIState();
const { isCamMuted, isMicMuted } = useMediaDevices();
const toggleCamera = (newState) => {
if (!callObject) return false;
return callObject.setLocalVideo(newState);
};
const toggleMic = (newState) => {
if (!callObject) return false;
return callObject.setLocalAudio(newState);
};
return (
<Tray>
<TrayButton
label="Camera"
onClick={() => toggleCamera(isCamMuted)}
orange={isCamMuted}
>
{isCamMuted ? <IconCameraOff /> : <IconCameraOn />}
</TrayButton>
<TrayButton
label="Mic"
onClick={() => toggleMic(isMicMuted)}
orange={isMicMuted}
>
{isMicMuted ? <IconMicOff /> : <IconMicOn />}
</TrayButton>
<TrayButton label="Settings" onClick={() => setShowDeviceModal(true)}>
<IconSettings />
</TrayButton>
<TrayButton
label="People"
onClick={() => setShowAside((p) => (p ? null : PEOPLE_ASIDE))}
>
<IconPeople />
</TrayButton>
{customTrayComponent}
<span className="divider" />
<TrayButton label="Leave" onClick={() => leave()} orange>
<IconLeave />
</TrayButton>
</Tray>
);
};
export default BasicTray;

View File

@ -1,2 +1,3 @@
export { Tray as default } from './Tray'; export { Tray as default } from './Tray';
export { Tray, TrayButton } from './Tray'; export { Tray, TrayButton } from './Tray';
export { BasicTray } from './BasicTray';

View File

@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
export const UIStateContext = createContext(); export const UIStateContext = createContext();
export const UIStateProvider = ({ asides, children }) => { export const UIStateProvider = ({ asides, customTrayComponent, children }) => {
const [showDeviceModal, setShowDeviceModal] = useState(false); const [showDeviceModal, setShowDeviceModal] = useState(false);
const [showAside, setShowAside] = useState(); const [showAside, setShowAside] = useState();
@ -11,6 +11,7 @@ export const UIStateProvider = ({ asides, children }) => {
<UIStateContext.Provider <UIStateContext.Provider
value={{ value={{
asides, asides,
customTrayComponent,
showDeviceModal, showDeviceModal,
setShowDeviceModal, setShowDeviceModal,
showAside, showAside,
@ -25,6 +26,7 @@ export const UIStateProvider = ({ asides, children }) => {
UIStateProvider.propTypes = { UIStateProvider.propTypes = {
children: PropTypes.node, children: PropTypes.node,
asides: PropTypes.arrayOf(PropTypes.func), asides: PropTypes.arrayOf(PropTypes.func),
customTrayComponent: PropTypes.node,
}; };
export const useUIState = () => useContext(UIStateContext); export const useUIState = () => useContext(UIStateContext);

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><title>comments</title><g stroke-linecap="round" stroke-linejoin="round" stroke-width="2" fill="none" stroke="currentColor"><path d="M23,5V16a2,2,0,0,1-2,2H19v4l-6-4H12" stroke="currentColor"></path><path d="M17,2H3A2,2,0,0,0,1,4v8a2,2,0,0,0,2,2H5v5l7-5h5a2,2,0,0,0,2-2V4A2,2,0,0,0,17,2Z"></path></g></svg>

After

Width:  |  Height:  |  Size: 389 B

View File

@ -0,0 +1,14 @@
import React from 'react';
import { TrayButton } from '@dailyjs/shared/components/Tray';
import { ReactComponent as IconChat } from '@dailyjs/shared/icons/chat-md.svg';
export const Tray = () => (
<>
<TrayButton label="Chat">
<IconChat />
</TrayButton>
</>
);
export default Tray;

View File

@ -0,0 +1 @@
export { Tray as default } from './Tray';

View File

@ -1,5 +1,9 @@
import React from 'react';
import App from '@dailyjs/basic-call/pages/_app'; import App from '@dailyjs/basic-call/pages/_app';
import Tray from '../components/Tray';
App.asides = []; App.asides = [];
App.customTrayComponent = <Tray />;
export default App; export default App;