diff --git a/dailyjs/README.md b/dailyjs/README.md index 5c3d2f6..4f3c0de 100644 --- a/dailyjs/README.md +++ b/dailyjs/README.md @@ -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 diff --git a/dailyjs/basic-call/components/App/App.js b/dailyjs/basic-call/components/App/App.js index 675af61..51d3524 100644 --- a/dailyjs/basic-call/components/App/App.js +++ b/dailyjs/basic-call/components/App/App.js @@ -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( () => (
{componentForState()} @@ -37,10 +49,28 @@ export const App = () => { ), [componentForState] ); -}; -App.propTypes = { - asides: PropTypes.arrayOf(PropTypes.func), + return ( + <> + {roomExp &&
{secs}
} {memoizedApp} + + + ); }; export default App; diff --git a/dailyjs/basic-call/components/CreatingRoom/CreatingRoom.js b/dailyjs/basic-call/components/CreatingRoom/CreatingRoom.js new file mode 100644 index 0000000..4973120 --- /dev/null +++ b/dailyjs/basic-call/components/CreatingRoom/CreatingRoom.js @@ -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 ( +
+ {fetching && ( +
+ Creating new demo room... +
+ )} + {error && ( + + An error occured + + {error} + An error occured when trying to create a demo room. Please check + that your environmental variables are correct and try again. + + + )} + + +
+ ); +}; + +CreatingRoom.propTypes = { + onCreated: PropTypes.func.isRequired, +}; + +export default CreatingRoom; diff --git a/dailyjs/basic-call/components/CreatingRoom/index.js b/dailyjs/basic-call/components/CreatingRoom/index.js new file mode 100644 index 0000000..c92b6f2 --- /dev/null +++ b/dailyjs/basic-call/components/CreatingRoom/index.js @@ -0,0 +1,2 @@ +export { CreatingRoom as default } from './CreatingRoom'; +export { CreatingRoom } from './CreatingRoom'; diff --git a/dailyjs/basic-call/pages/api/createRoom.js b/dailyjs/basic-call/pages/api/createRoom.js new file mode 100644 index 0000000..1c8ff2b --- /dev/null +++ b/dailyjs/basic-call/pages/api/createRoom.js @@ -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); +} diff --git a/dailyjs/basic-call/pages/index.js b/dailyjs/basic-call/pages/index.js index 1e0d432..7c0df78 100644 --- a/dailyjs/basic-call/pages/index.js +++ b/dailyjs/basic-call/pages/index.js @@ -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 (
- {!isConfigured ? ( - - ) : ( - - fetchToken ? getMeetingToken(room, isOwner) : setRoomName(room) - } - /> - )} + {(() => { + if (!isConfigured) return ; + if (demoMode) return ; + return ( + + fetchToken ? getMeetingToken(room, isOwner) : setRoomName(room) + } + /> + ); + })()}