From b235b9a2112a68a5fb12c3e3ed73c4522874027b Mon Sep 17 00:00:00 2001 From: Kimberlee Johnson Date: Wed, 15 Sep 2021 19:01:31 -0700 Subject: [PATCH] Componentize-ing, styling tweaks, README updates, typos --- prebuilt-ui/basic-embed/README.md | 5 +- prebuilt-ui/basic-embed/components/Call.js | 119 ++++++++ .../basic-embed/components/CreateRoom.js | 42 +++ prebuilt-ui/basic-embed/components/Header.js | 81 ------ prebuilt-ui/basic-embed/components/Home.js | 66 +++++ .../basic-embed/components/PrebuiltCall.js | 254 ------------------ .../basic-embed/pages/api/room/index.js | 4 +- prebuilt-ui/basic-embed/pages/index.js | 63 ++++- 8 files changed, 286 insertions(+), 348 deletions(-) create mode 100644 prebuilt-ui/basic-embed/components/Call.js create mode 100644 prebuilt-ui/basic-embed/components/CreateRoom.js delete mode 100644 prebuilt-ui/basic-embed/components/Header.js create mode 100644 prebuilt-ui/basic-embed/components/Home.js delete mode 100644 prebuilt-ui/basic-embed/components/PrebuiltCall.js 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 = () => ( -
-
- Daily -
Prebuilt demo
-
-
-
- API docs -
- - - Ocotocat - -
- -
-); - -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 ? ( + + ) : ( + + )} +
- +
); }