diff --git a/dailyjs/README.md b/dailyjs/README.md index 025f916..885bbc7 100644 --- a/dailyjs/README.md +++ b/dailyjs/README.md @@ -1,31 +1,29 @@ # Daily JS Examples -Run an examples via `yarn workspace @dailyjs/basic-call dev` (replacing `basic-call` with the name of the demo) from the project root +### [🤙 Basic call](./basic-call) -Note: please ensure your rooms are setup to use [web sockets](https://docs.daily.co/reference#domain-configuration) +The basic call demo (derived from our prebuilt UI codebase) demonstrates how to create a video and audio call using Call Object mode. -Note: examples are served using [nextjs](https://nextjs.org/) +### [💬 Text chat](./text-chat) + +Send messages to other participants using sendAppMessage --- ## Getting started -``` -// run locally, from project root -yarn -yarn workspace @dailyjs/[example-to-run] dev -``` - We recommend starting with the [basic call](./basic-call) example, showcasing the common flow of a call Daily call, device management and error handling. +Run an examples with `yarn workspace @dailyjs/[demo-name] dev` (replacing `[demo-name]` with the name of the demo you'd like to run e.g. `basic-call`. + +- Please ensure your Daily rooms are setup to use [web sockets](https://docs.daily.co/reference#domain-configuration) +- Follow the instructions within each demo first, making sure to set all the necassary local environment variables etc +- Examples are served using [nextjs](https://nextjs.org/) + ## Shared code These examples re-use some common components, contexts, hooks and libraries. These can be found in the [shared](./shared) folder. ---- +## Deploy your own on Vercel -## Where to get started? - -### [🤙 Basic call](./basic-call) - -The basic call demo (derived from our prebuilt UI codebase) demonstrates how to create a video and audio call using Call Object mode. +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/daily-co/clone-flow?repository-url=https%3A%2F%2Fgithub.com%2Fdaily-demos%2Fexamples.git&env=DAILY_DOMAIN%2CDAILY_API_KEY&envDescription=Your%20Daily%20domain%20and%20API%20key%20can%20be%20found%20on%20your%20account%20dashboard&envLink=https%3A%2F%2Fdashboard.daily.co&project-name=daily-examples&repo-name=daily-examples) diff --git a/dailyjs/basic-call/README.md b/dailyjs/basic-call/README.md index 037ae34..963240b 100644 --- a/dailyjs/basic-call/README.md +++ b/dailyjs/basic-call/README.md @@ -2,6 +2,12 @@ ![Basic Call](./image.png) +### Live example + +**[See it in action here ➡️](https://dailyjs-basic-call.vercel.app)** + +--- + ## What does this demo do? - Built on [NextJS](https://nextjs.org/) @@ -18,7 +24,7 @@ Please note: this demo is not currently mobile optimised ``` # set both DAILY_API_KEY and DAILY_DOMAIN -mv env.example env.local +mv env.example .env.local # from project root... yarn @@ -44,8 +50,6 @@ Abstraction hook that manages Daily call state and error handling **[ParticipantProvider.js](../shared/contexts/ParticipantProvider.js)** Manages participant state and abstracts common selectors / derived data -## Deploy your own +## Deploy your own on Vercel -Deploy the example using Vercel - -[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https%3A%2F%2Fgithub.com%2Fdaily-demos%2Fexamples%2Ftree%2Fmain%2Fdailyjs%2Fbasic-call&env=DAILY_DOMAIN,DAILY_API_KEY&project-name=dailyjs-basic-call&demo-title=Daily%20Basic%20Call%20Demo) +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/daily-co/clone-flow?repository-url=https%3A%2F%2Fgithub.com%2Fdaily-demos%2Fexamples.git&env=DAILY_DOMAIN%2CDAILY_API_KEY&envDescription=Your%20Daily%20domain%20and%20API%20key%20can%20be%20found%20on%20your%20account%20dashboard&envLink=https%3A%2F%2Fdashboard.daily.co&project-name=daily-examples&repo-name=daily-examples) diff --git a/dailyjs/basic-call/components/App/App.js b/dailyjs/basic-call/components/App/App.js index 0bf706e..675af61 100644 --- a/dailyjs/basic-call/components/App/App.js +++ b/dailyjs/basic-call/components/App/App.js @@ -2,16 +2,17 @@ import React, { 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, leave } = useCallState(); + const { state } = useCallState(); const componentForState = useCallUI({ state, - room: () => leave()} />, + room: () => , }); // Memoize children to avoid unnecassary renders from HOC @@ -38,4 +39,8 @@ export const App = () => { ); }; +App.propTypes = { + asides: PropTypes.arrayOf(PropTypes.func), +}; + export default App; diff --git a/dailyjs/basic-call/components/App/Asides.js b/dailyjs/basic-call/components/App/Asides.js index 0649b85..f78b4c8 100644 --- a/dailyjs/basic-call/components/App/Asides.js +++ b/dailyjs/basic-call/components/App/Asides.js @@ -1,10 +1,18 @@ import React from 'react'; -import { PeopleAside } from '@dailyjs/shared/components/Aside'; +import { PeopleAside } from '@dailyjs/shared/components/Aside/PeopleAside'; +import { useUIState } from '@dailyjs/shared/contexts/UIStateProvider'; -export const Asides = () => ( - <> - - -); +export const Asides = () => { + const { asides } = useUIState(); + + return ( + <> + + {asides.map((AsideComponent) => ( + + ))} + + ); +}; export default Asides; diff --git a/dailyjs/basic-call/components/Intro/Intro.js b/dailyjs/basic-call/components/Intro/Intro.js index be04274..301509e 100644 --- a/dailyjs/basic-call/components/Intro/Intro.js +++ b/dailyjs/basic-call/components/Intro/Intro.js @@ -16,7 +16,14 @@ import PropTypes from 'prop-types'; * --- * Specify which room we would like to join */ -export const Intro = ({ room, error, domain, onJoin, fetching = false }) => { +export const Intro = ({ + room, + error, + domain, + onJoin, + title, + fetching = false, +}) => { const [roomName, setRoomName] = useState(); const [owner, setOwner] = useState(false); const [fetchToken, setFetchToken] = useState(false); @@ -27,7 +34,7 @@ export const Intro = ({ room, error, domain, onJoin, fetching = false }) => { return ( - Daily Basic Call Example + {title} {error && ( @@ -67,6 +74,7 @@ export const Intro = ({ room, error, domain, onJoin, fetching = false }) => { Intro.propTypes = { room: PropTypes.string, + title: PropTypes.string, error: PropTypes.string, domain: PropTypes.string.isRequired, onJoin: PropTypes.func.isRequired, diff --git a/dailyjs/basic-call/components/Room/Room.js b/dailyjs/basic-call/components/Room/Room.js index 6072dfd..33d8cbd 100644 --- a/dailyjs/basic-call/components/Room/Room.js +++ b/dailyjs/basic-call/components/Room/Room.js @@ -1,47 +1,23 @@ import React from 'react'; import { Audio } from '@dailyjs/shared/components/Audio'; +import { BasicTray } from '@dailyjs/shared/components/Tray'; import { WaitingRoomModal, WaitingRoomNotification, } from '@dailyjs/shared/components/WaitingRoom'; -import { useCallState } from '@dailyjs/shared/contexts/CallProvider'; -import { useMediaDevices } from '@dailyjs/shared/contexts/MediaDeviceProvider'; import { useParticipants } from '@dailyjs/shared/contexts/ParticipantsProvider'; -import { useUIState } from '@dailyjs/shared/contexts/UIStateProvider'; import { useWaitingRoom } from '@dailyjs/shared/contexts/WaitingRoomProvider'; import useJoinSound from '@dailyjs/shared/hooks/useJoinSound'; -import { ReactComponent as IconCameraOff } from '@dailyjs/shared/icons/camera-off-md.svg'; -import { ReactComponent as IconCameraOn } from '@dailyjs/shared/icons/camera-on-md.svg'; -import { ReactComponent as IconLeave } from '@dailyjs/shared/icons/leave-md.svg'; -import { ReactComponent as IconMicOff } from '@dailyjs/shared/icons/mic-off-md.svg'; -import { ReactComponent as IconMicOn } from '@dailyjs/shared/icons/mic-on-md.svg'; -import { ReactComponent as IconPeople } from '@dailyjs/shared/icons/people-md.svg'; -import { ReactComponent as IconSettings } from '@dailyjs/shared/icons/settings-md.svg'; -import PropTypes from 'prop-types'; import { VideoGrid } from '../VideoGrid'; import { Header } from './Header'; -import { Tray, TrayButton } from './Tray'; -export const Room = ({ onLeave }) => { - const { callObject } = useCallState(); - const { setShowDeviceModal, setShowPeopleAside } = useUIState(); - const { isCamMuted, isMicMuted } = useMediaDevices(); +export const Room = () => { const { setShowModal, showModal } = useWaitingRoom(); const { localParticipant } = useParticipants(); useJoinSound(); - const toggleCamera = (newState) => { - if (!callObject) return false; - return callObject.setLocalVideo(newState); - }; - - const toggleMic = (newState) => { - if (!callObject) return false; - return callObject.setLocalAudio(newState); - }; - return (
@@ -60,39 +36,7 @@ export const Room = ({ onLeave }) => { )} - - toggleCamera(isCamMuted)} - orange={isCamMuted} - > - {isCamMuted ? : } - - toggleMic(isMicMuted)} - orange={isMicMuted} - > - {isMicMuted ? : } - - setShowDeviceModal(true)}> - - - - setShowPeopleAside((p) => !p)} - > - - - - - - - - - - +
-); - -TrayButton.propTypes = { - children: PropTypes.node, - onClick: PropTypes.func, - orange: PropTypes.bool, - label: PropTypes.string.isRequired, -}; - -export const Tray = ({ children }) => ( -
- {children} - -
-); - -Tray.propTypes = { - children: PropTypes.node, -}; - -export default Tray; diff --git a/dailyjs/basic-call/index.js b/dailyjs/basic-call/index.js new file mode 100644 index 0000000..9044efc --- /dev/null +++ b/dailyjs/basic-call/index.js @@ -0,0 +1 @@ +// Note: I am here because next-transpile-modules requires a mainfile diff --git a/dailyjs/basic-call/next.config.js b/dailyjs/basic-call/next.config.js index c223d3f..d054cbd 100644 --- a/dailyjs/basic-call/next.config.js +++ b/dailyjs/basic-call/next.config.js @@ -1,4 +1,10 @@ const withPlugins = require('next-compose-plugins'); const withTM = require('next-transpile-modules')(['@dailyjs/shared']); -module.exports = withPlugins([withTM]); +const packageJson = require('./package.json'); + +module.exports = withPlugins([withTM], { + env: { + PROJECT_TITLE: packageJson.description, + }, +}); diff --git a/dailyjs/basic-call/package.json b/dailyjs/basic-call/package.json index 7b5f48a..0bd5ae6 100644 --- a/dailyjs/basic-call/package.json +++ b/dailyjs/basic-call/package.json @@ -1,5 +1,6 @@ { "name": "@dailyjs/basic-call", + "description": "Basic Call Example", "version": "0.1.0", "private": true, "scripts": { @@ -18,5 +19,8 @@ "babel-plugin-module-resolver": "^4.1.0", "next-compose-plugins": "^2.2.1", "next-transpile-modules": "^8.0.0" + }, + "engines": { + "node": ">=0.12" } } diff --git a/dailyjs/basic-call/pages/_app.js b/dailyjs/basic-call/pages/_app.js index 3237e3a..e1c376c 100644 --- a/dailyjs/basic-call/pages/_app.js +++ b/dailyjs/basic-call/pages/_app.js @@ -1,4 +1,5 @@ import React from 'react'; +import GlobalHead from '@dailyjs/shared/components/GlobalHead'; import GlobalStyle from '@dailyjs/shared/components/GlobalStyle'; import Head from 'next/head'; import PropTypes from 'prop-types'; @@ -7,15 +8,16 @@ function App({ Component, pageProps }) { return ( <> - Daily - Basic Call Example - - + Daily - {process.env.PROJECT_TITLE} + - + ); } @@ -30,4 +32,8 @@ App.propTypes = { pageProps: PropTypes.object, }; +App.asides = []; +App.customTrayComponent = null; +App.customAppComponent = null; + export default App; diff --git a/dailyjs/basic-call/pages/api/token.js b/dailyjs/basic-call/pages/api/token.js index 617a9cf..37137da 100644 --- a/dailyjs/basic-call/pages/api/token.js +++ b/dailyjs/basic-call/pages/api/token.js @@ -21,7 +21,9 @@ export default async function handler(req, res) { }; const dailyRes = await fetch( - `${process.env.DAILY_REST_DOMAIN}/meeting-tokens`, + `${ + process.env.DAILY_REST_DOMAIN || 'https://api.daily.co/v1' + }/meeting-tokens`, options ); diff --git a/dailyjs/basic-call/pages/index.js b/dailyjs/basic-call/pages/index.js index b55c5ce..e0320c9 100644 --- a/dailyjs/basic-call/pages/index.js +++ b/dailyjs/basic-call/pages/index.js @@ -17,7 +17,13 @@ import { Intro, NotConfigured } from '../components/Intro'; * - Set call owner status * - Finally, renders the main application loop */ -export default function Index({ domain, isConfigured = false }) { +export default function Index({ + domain, + isConfigured = false, + asides, + customTrayComponent, + customAppComponent, +}) { const [roomName, setRoomName] = useState(''); const [fetchingToken, setFetchingToken] = useState(false); const [token, setToken] = useState(); @@ -66,6 +72,7 @@ export default function Index({ domain, isConfigured = false }) { ) : ( + - + {customAppComponent || } @@ -110,6 +117,9 @@ export default function Index({ domain, isConfigured = false }) { Index.propTypes = { isConfigured: PropTypes.bool.isRequired, domain: PropTypes.string, + asides: PropTypes.arrayOf(PropTypes.func), + customTrayComponent: PropTypes.node, + customAppComponent: PropTypes.node, }; export async function getStaticProps() { @@ -119,6 +129,9 @@ export async function getStaticProps() { // Pass through domain as prop return { - props: { domain: process.env.DAILY_DOMAIN || null, isConfigured }, + props: { + domain: process.env.DAILY_DOMAIN || null, + isConfigured, + }, }; } diff --git a/dailyjs/basic-call/public/message.mp3 b/dailyjs/basic-call/public/message.mp3 new file mode 100644 index 0000000..a067315 Binary files /dev/null and b/dailyjs/basic-call/public/message.mp3 differ diff --git a/dailyjs/shared/components/Aside/Aside.js b/dailyjs/shared/components/Aside/Aside.js index 1f717ef..669f32d 100644 --- a/dailyjs/shared/components/Aside/Aside.js +++ b/dailyjs/shared/components/Aside/Aside.js @@ -22,6 +22,8 @@ export const Aside = ({ onClose, children }) => ( .call-aside { background: white; position: relative; + flex-shrink: 0; + flex-grow: 0; width: ${ASIDE_WIDTH}px; height: 100vh; box-sizing: border-box; @@ -32,6 +34,9 @@ export const Aside = ({ onClose, children }) => ( .call-aside .inner { overflow-x: hidden; overflow-y: scroll; + height: 100%; + display: flex; + flex-flow: column wrap; } .call-aside .close { diff --git a/dailyjs/shared/components/Aside/PeopleAside.js b/dailyjs/shared/components/Aside/PeopleAside.js index b9b0ce5..88ee50f 100644 --- a/dailyjs/shared/components/Aside/PeopleAside.js +++ b/dailyjs/shared/components/Aside/PeopleAside.js @@ -10,6 +10,8 @@ import { useParticipants } from '../../contexts/ParticipantsProvider'; import { useUIState } from '../../contexts/UIStateProvider'; import { Button } from '../Button'; +export const PEOPLE_ASIDE = 'people'; + const PersonRow = ({ participant, isOwner = false }) => (
@@ -93,15 +95,15 @@ PersonRow.propTypes = { export const PeopleAside = () => { const { callObject } = useCallState(); - const { showPeopleAside, setShowPeopleAside } = useUIState(); + const { showAside, setShowAside } = useUIState(); const { allParticipants, isOwner } = useParticipants(); - if (!showPeopleAside) { + if (!showAside || showAside !== PEOPLE_ASIDE) { return null; } return ( -