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)
+ }
+ />
+ );
+ })()}