added demo mode

This commit is contained in:
Jon 2021-07-15 13:16:23 +01:00
parent c716c455a3
commit 1068a9f753
9 changed files with 210 additions and 24 deletions

View File

@ -12,6 +12,10 @@ Send messages to other participants using sendAppMessage
Broadcast call to a custom RTMP endpoint using a variety of different layout modes
### [⏺️ Recording](./recording)
Record a call video and audio using both cloud and local modes
### [🔥 Flying emojis](./flying-emojis)
Send emoji reactions to all clients using sendAppMessage

View File

@ -1,14 +1,26 @@
import React, { useMemo } from 'react';
import React, { useState, useEffect, useMemo } from 'react';
import { useCallState } from '@dailyjs/shared/contexts/CallProvider';
import { useCallUI } from '@dailyjs/shared/hooks/useCallUI';
import PropTypes from 'prop-types';
import Room from '../Room';
import { Asides } from './Asides';
import { Modals } from './Modals';
export const App = () => {
const { state } = useCallState();
const { roomExp, state } = useCallState();
const [secs, setSecs] = useState();
// If room has an expiry time, we'll calculate how many seconds until expiry
useEffect(() => {
if (!roomExp) {
return false;
}
const i = setInterval(() => {
const timeLeft = Math.round((roomExp - Date.now()) / 1000);
setSecs(`${Math.floor(timeLeft / 60)}:${`0${timeLeft % 60}`.slice(-2)}`);
}, 1000);
return () => clearInterval(i);
}, [roomExp]);
const componentForState = useCallUI({
state,
@ -16,7 +28,7 @@ export const App = () => {
});
// Memoize children to avoid unnecassary renders from HOC
return useMemo(
const memoizedApp = useMemo(
() => (
<div className="app">
{componentForState()}
@ -37,10 +49,28 @@ export const App = () => {
),
[componentForState]
);
};
App.propTypes = {
asides: PropTypes.arrayOf(PropTypes.func),
return (
<>
{roomExp && <div className="countdown">{secs}</div>} {memoizedApp}
<style jsx>{`
.countdown {
position: fixed;
top: 0px;
right: 0px;
width: 48px;
text-align: center;
padding: 4px 0;
font-size: 0.875rem;
font-weight: var(--weight-medium);
border-radius: 0 0 0 var(--radius-sm);
background: var(--blue-dark);
color: white;
z-index: 999;
}
`}</style>
</>
);
};
export default App;

View File

@ -0,0 +1,100 @@
import React, { useState, useEffect } from 'react';
import { Card, CardHeader, CardBody } from '@dailyjs/shared/components/Card';
import Loader from '@dailyjs/shared/components/Loader';
import { Well } from '@dailyjs/shared/components/Well';
import PropTypes from 'prop-types';
export const CreatingRoom = ({ onCreated }) => {
const [room, setRoom] = useState();
const [fetching, setFetching] = useState(false);
const [error, setError] = useState(false);
useEffect(() => {
if (room) return;
async function createRoom() {
setError(false);
setFetching(true);
console.log(`🚪 Creating new demo room...`);
// Create a room server side (using Next JS serverless)
const res = await fetch('/api/createRoom', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
});
const resJson = await res.json();
if (resJson.name) {
setFetching(false);
setRoom(resJson.name);
return;
}
setError(resJson.error || 'An unknown error occured');
setFetching(false);
}
createRoom();
}, [room]);
useEffect(() => {
if (!room || !onCreated) return;
console.log(`🚪 Room created: ${room}, joining now`);
onCreated(room, true);
}, [room, onCreated]);
return (
<div className="creating-room">
{fetching && (
<div className="creating">
<Loader /> Creating new demo room...
</div>
)}
{error && (
<Card error>
<CardHeader>An error occured</CardHeader>
<CardBody>
<Well variant="error">{error}</Well>
An error occured when trying to create a demo room. Please check
that your environmental variables are correct and try again.
</CardBody>
</Card>
)}
<style jsx>
{`
.creating-room {
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
color: white;
max-width: 420px;
margin: 0 auto;
}
.creating-room .creating {
display: flex;
}
.creating-room :global(.loader) {
margin-right: var(--spacing-xxxs);
}
`}
</style>
</div>
);
};
CreatingRoom.propTypes = {
onCreated: PropTypes.func.isRequired,
};
export default CreatingRoom;

View File

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

View File

@ -0,0 +1,36 @@
export default async function handler(req, res) {
if (req.method === 'POST') {
console.log(`Creating room on domain ${process.env.DAILY_DOMAIN}`);
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.DAILY_API_KEY}`,
},
body: JSON.stringify({
properties: {
exp: Math.round(Date.now() / 1000) + 5 * 60, // expire in 5 minutes
eject_at_room_exp: true,
},
}),
};
const dailyRes = await fetch(
`${process.env.DAILY_REST_DOMAIN || 'https://api.daily.co/v1'}/rooms`,
options
);
const { name, url, error } = await dailyRes.json();
if (error) {
return res.status(500).json({ error });
}
return res
.status(200)
.json({ name, url, domain: process.env.DAILY_DOMAIN });
}
return res.status(500);
}

View File

@ -6,9 +6,9 @@ import { TracksProvider } from '@dailyjs/shared/contexts/TracksProvider';
import { UIStateProvider } from '@dailyjs/shared/contexts/UIStateProvider';
import { WaitingRoomProvider } from '@dailyjs/shared/contexts/WaitingRoomProvider';
import getDemoProps from '@dailyjs/shared/lib/demoProps';
import PropTypes from 'prop-types';
import App from '../components/App';
import { CreatingRoom } from '../components/CreatingRoom';
import { Intro, NotConfigured } from '../components/Intro';
/**
@ -25,6 +25,7 @@ export default function Index({
predefinedRoom = '',
forceFetchToken = false,
forceOwner = false,
demoMode = false,
asides,
modals,
customTrayComponent,
@ -74,22 +75,24 @@ export default function Index({
if (!isReady) {
return (
<main>
{!isConfigured ? (
<NotConfigured />
) : (
<Intro
forceFetchToken={forceFetchToken}
forceOwner={forceOwner}
title={process.env.PROJECT_TITLE}
room={roomName}
error={tokenError}
fetching={fetchingToken}
domain={domain}
onJoin={(room, isOwner, fetchToken) =>
fetchToken ? getMeetingToken(room, isOwner) : setRoomName(room)
}
/>
)}
{(() => {
if (!isConfigured) return <NotConfigured />;
if (demoMode) return <CreatingRoom onCreated={getMeetingToken} />;
return (
<Intro
forceFetchToken={forceFetchToken}
forceOwner={forceOwner}
title={process.env.PROJECT_TITLE}
room={roomName}
error={tokenError}
fetching={fetchingToken}
domain={domain}
onJoin={(room, isOwner, fetchToken) =>
fetchToken ? getMeetingToken(room, isOwner) : setRoomName(room)
}
/>
);
})()}
<style jsx>{`
height: 100vh;
@ -136,6 +139,7 @@ Index.propTypes = {
customAppComponent: PropTypes.node,
forceFetchToken: PropTypes.bool,
forceOwner: PropTypes.bool,
demoMode: PropTypes.bool,
};
export async function getStaticProps() {

View File

@ -34,6 +34,7 @@ export const CallProvider = ({
const [preJoinNonAuthorized, setPreJoinNonAuthorized] = useState(false);
const [enableRecording, setEnableRecording] = useState(null);
const [startCloudRecording, setStartCloudRecording] = useState(false);
const [roomExp, setRoomExp] = useState(null);
// Daily CallMachine hook (primarily handles status of the call)
const { daily, leave, state, setRedirectOnLeave } = useCallMachine({
@ -50,6 +51,11 @@ export const CallProvider = ({
const roomConfig = await daily.room();
if (!('config' in roomConfig)) return;
if (roomConfig?.config?.exp) {
setRoomExp(
roomConfig?.config?.exp * 1000 || Date.now() + 1 * 60 * 1000
);
}
const browser = Bowser.parse(window.navigator.userAgent);
const supportsRecording =
browser.platform.type === 'desktop' && browser.engine.name === 'Blink';
@ -100,6 +106,7 @@ export const CallProvider = ({
addFakeParticipant,
preJoinNonAuthorized,
leave,
roomExp,
videoQuality,
enableRecording,
setVideoQuality,

View File

@ -57,6 +57,7 @@ export const UIStateProvider = ({
UIStateProvider.propTypes = {
children: PropTypes.node,
demoMode: PropTypes.bool,
asides: PropTypes.arrayOf(PropTypes.func),
modals: PropTypes.arrayOf(PropTypes.func),
customTrayComponent: PropTypes.node,

View File

@ -5,5 +5,7 @@ export default function getDemoProps() {
isConfigured: !!process.env.DAILY_DOMAIN && !!process.env.DAILY_API_KEY,
// Have we predefined a room to use?
predefinedRoom: process.env.DAILY_ROOM || '',
// Are we running in demo mode? (automatically creates a short-expiry room)
demoMode: !!process.env.DAILY_DEMO_MODE,
};
}