diff --git a/prebuilt-ui/basic-embed/README.md b/prebuilt-ui/basic-embed/README.md
index ddbd17e..7ec5319 100644
--- a/prebuilt-ui/basic-embed/README.md
+++ b/prebuilt-ui/basic-embed/README.md
@@ -4,7 +4,7 @@
## How the demo works
-This demo embeds [Daily Prebuilt](https://www.daily.co/prebuilt), a ready-to-use video chat interface, into a Next.js site. It makes use of [Next API routes](https://nextjs.org/docs/api-routes/introduction) to create a Daily room server-side.
+This demo embeds [Daily Prebuilt](https://www.daily.co/prebuilt), a ready-to-use video chat interface, into a Next.js site. It makes use of [Next API routes](https://nextjs.org/docs/api-routes/introduction) to create Daily rooms server-side.
## Requirements
@@ -15,7 +15,8 @@ You can also paste an existing Daily room into the input. The room URL should be
# Running locally
1. Copy .env.example and change it to an .env.local with your own DAILY_API_KEY and DAILY_DOMAIN
2. `cd basic-embed`
-3. yarn dev
+3. yarn
+4. yarn workspace @prebuilt-ui/basic-embed dev
Or...
diff --git a/prebuilt-ui/basic-embed/components/Call.js b/prebuilt-ui/basic-embed/components/Call.js
new file mode 100644
index 0000000..164d90c
--- /dev/null
+++ b/prebuilt-ui/basic-embed/components/Call.js
@@ -0,0 +1,119 @@
+import DailyIframe from '@daily-co/daily-js';
+import React, { useCallback, useEffect, useRef, useState } from 'react';
+import { writeText } from 'clipboard-polyfill';
+import { Button } from '@dailyjs/shared/components/Button';
+import {
+ Card,
+ CardBody,
+ CardHeader,
+ CardFooter,
+} from '@dailyjs/shared/components/Card';
+import { ExpiryTimer } from '@dailyjs/shared/components/ExpiryTimer';
+import { TextInput } from '@dailyjs/shared/components/Input';
+
+const CALL_OPTIONS = {
+ showLeaveButton: true,
+ iframeStyle: {
+ height: '100%',
+ width: '100%',
+ aspectRatio: 16 / 9,
+ minwidth: '400px',
+ maxWidth: '920px',
+ border: '0',
+ borderRadius: '12px',
+ },
+};
+
+export default function Call({
+ room,
+ setRoom,
+ callFrame,
+ setCallFrame,
+ expiry,
+}) {
+ const callRef = useRef(null);
+ const [isLinkCopied, setIsLinkCopied] = useState(false);
+
+ const handleCopyClick = useCallback(() => {
+ writeText(room);
+ setIsLinkCopied(true);
+ setTimeout(() => setIsLinkCopied(false), 5000);
+ }, [room, isLinkCopied]);
+
+ const createAndJoinCall = useCallback(() => {
+ const newCallFrame = DailyIframe.createFrame(
+ callRef?.current,
+ CALL_OPTIONS
+ );
+
+ setCallFrame(newCallFrame);
+
+ newCallFrame.join({ url: room });
+
+ const leaveCall = () => {
+ setRoom(null);
+ setCallFrame(null);
+ callFrame.destroy();
+ };
+
+ newCallFrame.on('left-meeting', leaveCall);
+ });
+
+ /**
+ * Initiate Daily iframe creation on component render if it doesn't already exist
+ */
+ useEffect(() => {
+ if (callFrame) return;
+
+ createAndJoinCall();
+ }, [callFrame, createAndJoinCall]);
+
+ return (
+
+ {/* Daily iframe container */}
+
+
+ Copy and share the URL to invite others
+
+
+
+
+
+ {expiry && }
+
+
+
+ );
+}
diff --git a/prebuilt-ui/basic-embed/components/CreateRoom.js b/prebuilt-ui/basic-embed/components/CreateRoom.js
new file mode 100644
index 0000000..85f1849
--- /dev/null
+++ b/prebuilt-ui/basic-embed/components/CreateRoom.js
@@ -0,0 +1,42 @@
+import React, { useState } from 'react';
+import { Well } from '@dailyjs/shared/components/Well';
+import { Button } from '@dailyjs/shared/components/Button';
+
+export function CreateRoom({ isConfigured, isValidRoom, setRoom, setExpiry }) {
+ const [isError, setIsError] = useState(false);
+
+ /**
+ * Send a request to create a Daily room server-side via Next API routes, then set the returned url in local state to trigger Daily iframe creation in
+ */
+ const createRoom = async () => {
+ try {
+ const res = await fetch('/api/room', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+ const resJson = await res.json();
+ setExpiry(resJson.config?.exp);
+ setRoom(resJson.url);
+ } catch (e) {
+ setIsError(true);
+ }
+ };
+ return (
+ <>
+ {!isConfigured && (
+
+ You must configure env variables to create rooms (see README
+ instructions).
+
+ )}
+ {isError && (
+ Error creating the room. Please try again.
+ )}
+
+ >
+ );
+}
diff --git a/prebuilt-ui/basic-embed/components/Header.js b/prebuilt-ui/basic-embed/components/Header.js
deleted file mode 100644
index 06affa5..0000000
--- a/prebuilt-ui/basic-embed/components/Header.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import React from 'react';
-
-export const Header = () => (
-
-
-

-
Prebuilt demo
-
-
-
-
-);
-
-export default Header;
diff --git a/prebuilt-ui/basic-embed/components/Home.js b/prebuilt-ui/basic-embed/components/Home.js
new file mode 100644
index 0000000..44395bd
--- /dev/null
+++ b/prebuilt-ui/basic-embed/components/Home.js
@@ -0,0 +1,66 @@
+import React, { useCallback, useRef, useState } from 'react';
+import { Button } from '@dailyjs/shared/components/Button';
+import {
+ Card,
+ CardBody,
+ CardFooter,
+ CardHeader,
+} from '@dailyjs/shared/components/Card';
+import { CreateRoom } from '../components/CreateRoom';
+import { Field } from '@dailyjs/shared/components/Field';
+import { TextInput } from '@dailyjs/shared/components/Input';
+
+export default function Home({ setRoom, setExpiry, isConfigured }) {
+ const roomRef = useRef(null);
+ const [isValidRoom, setIsValidRoom] = useState(false);
+
+ /**
+ * If the room is valid, setIsValidRoom and enable the join button
+ */
+ const checkValidity = useCallback(
+ (e) => {
+ if (e?.target?.checkValidity()) {
+ setIsValidRoom(true);
+ }
+ },
+ [isValidRoom]
+ );
+
+ /**
+ * Set the roomUrl in local state to trigger Daily iframe creation in
+ */
+ const joinCall = useCallback(() => {
+ const roomUrl = roomRef?.current?.value;
+ setRoom(roomUrl);
+ }, [roomRef]);
+
+ return (
+
+
+ Start demo with a new unique room, or paste in your own room URL
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/prebuilt-ui/basic-embed/components/PrebuiltCall.js b/prebuilt-ui/basic-embed/components/PrebuiltCall.js
deleted file mode 100644
index 7474777..0000000
--- a/prebuilt-ui/basic-embed/components/PrebuiltCall.js
+++ /dev/null
@@ -1,254 +0,0 @@
-import DailyIframe from '@daily-co/daily-js';
-import React, {
- useCallback,
- useEffect,
- useMemo,
- useRef,
- useState,
-} from 'react';
-import { writeText } from 'clipboard-polyfill';
-import { Button } from '@dailyjs/shared/components/Button';
-import {
- Card,
- CardBody,
- CardFooter,
- CardHeader,
-} from '@dailyjs/shared/components/Card';
-import Field from '@dailyjs/shared/components/Field';
-import { TextInput } from '@dailyjs/shared/components/Input';
-import { Well } from '@dailyjs/shared/components/Well';
-import { Header } from '../components/Header';
-
-export default function PrebuiltCall(props) {
- const [demoState, setDemoState] = useState('home');
- const [isError, setIsError] = useState(false);
- const [roomURL, setRoomURL] = useState('');
- const [exp, setExp] = useState();
- const [secs, setSecs] = useState();
- const [roomValidity, setRoomValidity] = useState(false);
- const roomURLRef = useRef(null);
- const iframeRef = useRef(null);
- const callFrame = useRef(null);
- const [linkCopied, setLinkCopied] = useState(false);
-
- // Updates the time left that displays in the UI
- useEffect(() => {
- if (!exp) {
- return false;
- }
- const i = setInterval(() => {
- const timeLeft = Math.floor((new Date(exp * 1000) - Date.now()) / 1000);
- setSecs(`${Math.floor(timeLeft / 60)}:${`0${timeLeft % 60}`.slice(-2)}`);
- }, 1000);
- return () => clearInterval(i);
- }, [exp]);
-
- // Listens for a "call" demo state, and creates then joins a callFrame as soon as that happens
- useEffect(() => {
- if (!iframeRef?.current || demoState !== 'call') {
- return;
- }
- try {
- callFrame.current = DailyIframe.createFrame(iframeRef.current, {
- showLeaveButton: true,
- iframeStyle: {
- height: '100%',
- width: '100%',
- aspectRatio: 16 / 9,
- minwidth: '400px',
- maxWidth: '920px',
- border: '0',
- borderRadius: '12px',
- },
- });
- callFrame.current.join({
- url: roomURL,
- });
- } catch (e) {
- setDemoState('home');
- setIsError(true);
- return;
- }
-
- const handleLeftMeeting = () => {
- setDemoState('home');
- setRoomValidity(false);
- callFrame.current.destroy();
- };
-
- callFrame.current.on('left-meeting', handleLeftMeeting);
- }, [demoState, iframeRef, roomURL]);
-
- const createRoom = useCallback(
- async (e) => {
- if (!roomURLRef?.current.value) {
- const roomExp = Math.round(Date.now() / 1000) + 60 * 5;
- try {
- const res = await fetch('/api/room', {
- method: 'POST',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- properties: {
- roomExp,
- },
- }),
- });
- const roomJson = await res.json();
- const { url } = roomJson;
- setRoomURL(url);
- setDemoState('call');
- setExp(roomExp);
- setIsError(false);
- } catch (e) {
- setDemoState('home');
- setIsError(true);
- }
- }
- },
- [roomURL, exp]
- );
-
- // Updates state if a room is provided
- const handleRoomInput = useCallback(
- (e) => {
- setRoomURL(e?.target?.value);
- if (e?.target?.checkValidity()) {
- setRoomValidity(true);
- console.log(roomValidity);
- }
- },
- [roomValidity]
- );
-
- const submitJoinRoom = useCallback(() => {
- setDemoState('call');
- });
-
- const handleCopyClick = useCallback(() => {
- console.log('click');
- writeText(roomURL);
- setLinkCopied(true);
- setTimeout(() => setLinkCopied(false), 5000);
- }, [roomURL, linkCopied]);
-
- const content = useMemo(() => {
- switch (demoState) {
- case 'home':
- return (
-
-
- Start demo with a new unique room, or paste in your own room URL.
-
-
- {!props.configured && (
-
- You must configure env variables to create rooms (see README
- instructions).
-
- )}
- {isError && (
-
- Error creating the room. Please try again.
-
- )}
-
-
-
-
-
-
-
-
-
- );
- case 'call':
- return (
- <>
-
-
- Copy and share the URL to invite others.
-
-
-
-
- {exp && (
-
- This room expires in:{' '}
- {secs}
-
- )}
-
-
- >
- );
- }
- }, [demoState, roomValidity, roomURLRef, exp, secs]);
-
- return (
-
-
- {content}
-
-
- );
-}
diff --git a/prebuilt-ui/basic-embed/pages/api/room/index.js b/prebuilt-ui/basic-embed/pages/api/room/index.js
index 80caa62..e4039c5 100644
--- a/prebuilt-ui/basic-embed/pages/api/room/index.js
+++ b/prebuilt-ui/basic-embed/pages/api/room/index.js
@@ -3,8 +3,6 @@
*/
export default async function handler(req, res) {
- const { roomExp } = req.body.properties;
-
if (req.method === 'POST') {
const options = {
method: 'POST',
@@ -19,7 +17,7 @@ export default async function handler(req, res) {
enable_network_ui: true,
enable_screenshare: true,
enable_chat: true,
- exp: roomExp,
+ exp: Math.round(Date.now() / 1000) + 5 * 60,
eject_at_room_exp: true,
},
}),
diff --git a/prebuilt-ui/basic-embed/pages/index.js b/prebuilt-ui/basic-embed/pages/index.js
index 209542a..ee1c401 100644
--- a/prebuilt-ui/basic-embed/pages/index.js
+++ b/prebuilt-ui/basic-embed/pages/index.js
@@ -1,17 +1,64 @@
-import PrebuiltCall from '../components/PrebuiltCall';
+// import PrebuiltCall from '../components/PrebuiltCall';
+import React, { useState } from 'react';
+import Call from '../components/Call';
+import Home from '../components/Home';
+import Header from '@dailyjs/shared/components/Header';
import getDemoProps from '@dailyjs/shared/lib/demoProps';
export default function Index({ isConfigured = false }) {
+ const [room, setRoom] = useState(null);
+ const [expiry, setExpiry] = useState(null);
+ const [callFrame, setCallFrame] = useState(null);
+
return (
- <>
-
+
+
+
+ {room ? (
+
+ ) : (
+
+ )}
+
- >
+
);
}