added demo mode
This commit is contained in:
parent
c716c455a3
commit
1068a9f753
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
export { CreatingRoom as default } from './CreatingRoom';
|
||||
export { CreatingRoom } from './CreatingRoom';
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue