diff --git a/custom/fitness-demo/.babelrc b/custom/fitness-demo/.babelrc new file mode 100644 index 0000000..a6f4434 --- /dev/null +++ b/custom/fitness-demo/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["next/babel"], + "plugins": ["inline-react-svg"] +} diff --git a/custom/fitness-demo/.gitignore b/custom/fitness-demo/.gitignore new file mode 100644 index 0000000..058f0ec --- /dev/null +++ b/custom/fitness-demo/.gitignore @@ -0,0 +1,35 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +node_modules +.pnp +.pnp.js + +# testing +/coverage + +# next.js +.next +out + +# production +build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel \ No newline at end of file diff --git a/custom/fitness-demo/README.md b/custom/fitness-demo/README.md new file mode 100644 index 0000000..648f221 --- /dev/null +++ b/custom/fitness-demo/README.md @@ -0,0 +1,55 @@ +# Basic call + +![Basic Call](./image.png) + +### Live example + +**[See it in action here ➡️](https://custom-basic-call.vercel.app)** + +--- + +## What does this demo do? + +- Built on [NextJS](https://nextjs.org/) +- Create a Daily instance using call object mode +- Manage user media devices +- Render UI based on the call state +- Handle media and call errors +- Obtain call access token via Daily REST API +- Handle preauthentication, knock for access and auto join + +Please note: this demo is not currently mobile optimised + +### Getting started + +``` +# set both DAILY_API_KEY and DAILY_DOMAIN +mv env.example .env.local + +# from project root... +yarn +yarn workspace @custom/basic-call dev +``` + +## How does this example work? + +This demo puts to work the following [shared libraries](../shared): + +**[MediaDeviceProvider.js](../shared/contexts/MediaDeviceProvider.js)** +Convenience context that provides an interface to media devices throughout app + +**[useDevices.js](../shared/contexts/useDevices.js)** +Hook for managing the enumeration and status of client media devices) + +**[CallProvider.js](../shared/contexts/CallProvider.js)** +Primary call context that manages Daily call state, participant state and call object interaction + +**[useCallMachine.js](../shared/contexts/useCallMachine.js)** +Abstraction hook that manages Daily call state and error handling + +**[ParticipantsProvider.js](../shared/contexts/ParticipantsProvider.js)** +Manages participant state and abstracts common selectors / derived data + +## Deploy your own on Vercel + +[![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/custom/fitness-demo/components/App/App.js b/custom/fitness-demo/components/App/App.js new file mode 100644 index 0000000..81b43d9 --- /dev/null +++ b/custom/fitness-demo/components/App/App.js @@ -0,0 +1,51 @@ +import React, { useMemo } from 'react'; +import ExpiryTimer from '@custom/shared/components/ExpiryTimer'; +import { useCallState } from '@custom/shared/contexts/CallProvider'; +import { useCallUI } from '@custom/shared/hooks/useCallUI'; + +import PropTypes from 'prop-types'; +import Room from '../Call/Room'; +import { Asides } from './Asides'; +import { Modals } from './Modals'; + +export const App = ({ customComponentForState }) => { + const { roomExp, state } = useCallState(); + + const componentForState = useCallUI({ + state, + room: , + ...customComponentForState, + }); + + // Memoize children to avoid unnecassary renders from HOC + return useMemo( + () => ( + <> + {roomExp && } +
+ {componentForState()} + + + +
+ + ), + [componentForState, roomExp] + ); +}; + +App.propTypes = { + customComponentForState: PropTypes.any, +}; + +export default App; diff --git a/custom/fitness-demo/components/App/Asides.js b/custom/fitness-demo/components/App/Asides.js new file mode 100644 index 0000000..4afbca0 --- /dev/null +++ b/custom/fitness-demo/components/App/Asides.js @@ -0,0 +1,20 @@ +import React from 'react'; +import { NetworkAside } from '@custom/shared/components/Aside'; +import { PeopleAside } from '@custom/shared/components/Aside'; +import { useUIState } from '@custom/shared/contexts/UIStateProvider'; + +export const Asides = () => { + const { asides } = useUIState(); + + return ( + <> + + + {asides.map((AsideComponent) => ( + + ))} + + ); +}; + +export default Asides; diff --git a/custom/fitness-demo/components/App/Modals.js b/custom/fitness-demo/components/App/Modals.js new file mode 100644 index 0000000..ba5c27c --- /dev/null +++ b/custom/fitness-demo/components/App/Modals.js @@ -0,0 +1,18 @@ +import React from 'react'; +import DeviceSelectModal from '@custom/shared/components/DeviceSelectModal/DeviceSelectModal'; +import { useUIState } from '@custom/shared/contexts/UIStateProvider'; + +export const Modals = () => { + const { modals } = useUIState(); + + return ( + <> + + {modals.map((ModalComponent) => ( + + ))} + + ); +}; + +export default Modals; diff --git a/custom/fitness-demo/components/App/index.js b/custom/fitness-demo/components/App/index.js new file mode 100644 index 0000000..7e7372b --- /dev/null +++ b/custom/fitness-demo/components/App/index.js @@ -0,0 +1 @@ +export { App as default } from './App'; diff --git a/custom/fitness-demo/components/Call/Container.js b/custom/fitness-demo/components/Call/Container.js new file mode 100644 index 0000000..22e0d08 --- /dev/null +++ b/custom/fitness-demo/components/Call/Container.js @@ -0,0 +1,49 @@ +import React, { useMemo } from 'react'; +import { Audio } from '@custom/shared/components/Audio'; +import { BasicTray } from '@custom/shared/components/Tray'; +import { useParticipants } from '@custom/shared/contexts/ParticipantsProvider'; +import useJoinSound from '@custom/shared/hooks/useJoinSound'; +import PropTypes from 'prop-types'; +import { WaitingRoom } from './WaitingRoom'; + +export const Container = ({ children }) => { + const { isOwner } = useParticipants(); + + useJoinSound(); + + const roomComponents = useMemo( + () => ( + <> + {/* Show waiting room notification & modal if call owner */} + {isOwner && } + {/* Tray buttons */} + + {/* Audio tags */} +