Part 2: Section 3 - Building a meeting application in React with Zoom APIs and SDKs

justzoomit

just-zoomit

Posted on March 28, 2023

Part 2: Section 3 - Building a meeting application in React with Zoom APIs and SDKs

Build Application components continued

So far we have everything we need to interact with Zoom REST APIs and start/join the Meeting SDK. In the second part of this section, we will focus on creating the necessary React Application components.

Buttons -- InstantMeetingButton

Next we will be developing the Instant Meeting Button component, which will provide users with the ability to join an instant meeting with a single click. To begin, go to the "Button" directory located in the src/pages folder. Inside this directory, run the commands below to create the "InstantMeetingButton.js" file:

// Working DIR: frontend/src/Home/Buttons

 cd ../Home/Buttons 
touch InstantMeetingButton.js
Enter fullscreen mode Exit fullscreen mode

InstantMeetingButton.js

Our next step involves creating a button that triggers the initiation of an instant Zoom meeting. To achieve this, we will make an API request to our application's backend, which will respond with the necessary information. Once we receive the response, we will use a specialized library called "useNavigate," which is built on the React framework to navigate to the Application SDK page and join the meeting successfully. To accomplish this, add the following code:

// Working Directory : frontend/src/components/pages/Dialogs
// File: InstantMeetingButton.js

import React from "react";
import { useNavigate } from "react-router-dom";

import { OrangeButton as InstantMeetingButton } from "./buttonComposition";


export function NewMeetingButton() {
  const navigate = useNavigate();

  const handleSubmit = async (event) => {
    event.preventDefault();

    try {
      const POST_OPTIONS = {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          type: 1,
        }),
      };

      const response = await fetch("/api/zoom/create", POST_OPTIONS);
      const json = await response.json();

      if (!response.ok) {
        throw new Error("Network response was not ok");
      }

      if (json.id && json.password) {
        navigate(`/msdk/?mn=${json.id}&pw=${json.password}`);
      } else {
        console.log("Error: No data received");
      }
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <InstantMeetingButton
          type="submit"
          text="videocam"
          label="New Meeting"
        />
      </form>
    </div>
  );
}



Enter fullscreen mode Exit fullscreen mode

Create Dialogs

Now we're going to create the component that will handle the process of joining a meeting through a dialog box. To get begin, in your terminal navigate to the Home directory and run the following commands to create a new directory called "Dialogs" and generate a new file named "JoinMeetingModal.js":

// Working DIR: frontend/src

cd ../ && mkdir Dialogs && cd  Dialogs 

touch JoinMeetingModal.js && touch Styles.css

Enter fullscreen mode Exit fullscreen mode

JoinMeetingModal

Our next step involves creating the dialog component, which will be developed using React Modal. This library provides an overlay on the screen, giving it visual precedence over all other elements. By using Modal, we can direct the user's attention to a specific point on the screen, show feedback based on our needs, and improve the user experience. The primary advantage of using modals is their independence from the active page, which enables them to add, update, delete, or view information without changing the current URL. Additionally, they are easy to open and close, and the background information is often fully or partially visible.

In the JoinMeetingModal.js file, add the following code:

import React, { useRef, useState } from "react";
import { useNavigate } from "react-router-dom";
import ReactDom from "react-dom";

import "./styles.css";

// Adpoted Component Composition pattern and pass data from child to parent pattern

export const JoinMeetingModal = ({ setShowModal }) => {
  const modalRef = useRef();

  const closeModal = (e) => {
    if (e.target === modalRef.current) {
      setShowModal(false);
    }
  };

  const [state, ] = useState({ role: 1 });
  const { role } = state;
  const id = useRef();
  const password = useRef();
  const navigate = useNavigate();

  const handleSubmit = (event) => {
    event.preventDefault();

    try {
      if (id.current.value === "" || password.current.value === "") {
        alert("Please enter a valid meeting ID and password");
      } else {
        setShowModal(false);
        navigate(`/msdk/?mn=${id.current.value}&pw=${password.current.value}`);
      }
    } catch (error) {
      console.error(error);
    }
  };

  // render the modal JSX in the portal div.
  return ReactDom.createPortal(
    <div className="container" ref={modalRef} onClick={closeModal}>
      <div className="modal">
      <h2>Join Meeting</h2>
        <div>
          <form onSubmit={handleSubmit}>
            <div>
              <input
                type="text"
                id="topic"
                placeholder="Meeting ID"
                ref={id}
                required={true}
              />
            </div>
            &nbsp; &nbsp;
            <div>
              <input
                type="text"
                id="topic"
                placeholder="Meeting Password"
                ref={password}
                required={true}
              />
            </div>
            <hr class="solid"></hr>
            <div>

              <button
                type="submit"
                style={{
                  background: "#808080",

                }}
                onClick={() => setShowModal(false)}
              >
                Cancel
              </button>

              &nbsp; &nbsp;

              <button
                type="submit"
                style={{ background: "#316efd" }}
              >
                {role === 1 ? "Join Meeting" : "Start Meeting"}
              </button>

            </div>

          </form>
        </div>
      </div>
    </div>,
    document.getElementById("portal")
  );
};

Enter fullscreen mode Exit fullscreen mode

Add Modal Styles -- (Convert To Styled Components)

Next we will use the styled-components library, which enables developers to write CSS inside their component files. This library is highly advantageous because it simplifies the process of working with props and state. With styled-components, we do not need to manually pass props to CSS; it is automatically available. This simplifies the process of writing styles that depend on data from the component. Furthermore, styled-components make it possible to keep everything in one file, making it easy to export and reuse components throughout the application.

In the styles.css file, add the following code:

#portal .container {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.7);
  }

  .container .modal {
    z-index: 1;
    width: 350px;
    height: 300px;
    background: white;
    display:grid;
    align-items: center;
    justify-content: center;
    border-radius: 5px;
    position: relative;
    animation: animate 0.3s;
  }

  .modal input {
    border-radius: 8px;
  }

  .modal button {
    position: relative;
    bottom: 0px;
    left: 7px;
    width: 140px;
    padding: 4px 5px;
    background: grey;
    color: white;
    font-weight: bold;
    border: none;
    outline: none;
    border-radius: 12px;
    cursor: pointer;
    float : left;
    margin-right: 7px;
  }

  @keyframes animate {
    from {
      transform: scale(0.5);
    }
    to {
      transform: scale(1);
    }
  }


Enter fullscreen mode Exit fullscreen mode

Install Table Dependencies

Our next step involves displaying the Zoom API response data on the UI. To achieve this, we will use the React Data Table Component, which is a simple yet flexible table library that comes with out-of-the-box features such as built-in sorting and pagination.

To install react-data-table-component, in the terminal, run the following command:


Working directory : frontend/src

cd ../../..
npm install -d react-data-table-component  


Enter fullscreen mode Exit fullscreen mode

Create Table

Now we're going to create the Table component directory, which will include the TableComponents.js file that will handle component styles and the dateTime.js file that will handle the rendering of the date. To begin, run the following commands in the src directory to create a new directory called "Table" and generate the necessary files - Table.js, TableComponents.js, and dateTime.js:

// Working DIR: frontend/src

cd pages/Home && mkdir Table && cd Table
touch Table.js TableComponents.js dateTime.js
Enter fullscreen mode Exit fullscreen mode

Date & Time

The Date & Time will handle render the date and to the table. In the dateTime.js file, add the following code:


// Working Directory : frontend/src/components/pages/Home/Table/
// File: dateTime.js

const timeOptions = { hour: "2-digit", minute: "2-digit" };
const dateOptions = {
  weekday: "long",
  year: "numeric",
  month: "long",
  day: "numeric",
};

export const element = (
  <div>
    <div
      style={{
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
      }}
    >
      <h1>{new Date().toLocaleTimeString([], timeOptions)}</h1>
      <h2>{new Date().toLocaleDateString("en-us", dateOptions)}</h2>
    </div>
  </div>
);

Enter fullscreen mode Exit fullscreen mode

Styled Components : TableComponents.js

Next lets create the table styles in a separate file and exporting styled components from it. To achieve this, add the following code to the TableComponents.js file, and then we can import them in the desired files.

In the TableComponents.js file, add the following code:

// Working Directory : frontend/src/components/pages/Home/Table/


import styled from 'styled-components';

const CenterDiv = styled.div`
display: "flex";
flexDirection: "column";
alignItems: "center";
`;

const TableContainer = styled.div`
border: solid .2em #f5f5f5;  
border-radius: 2.5em;
width: auto;
height: auto;
background-color:#ffffff;
`;


const HoverButton = styled.button`
  transition: transform 0.2s cubic-bezier(0.235, 0, 0.05, 0.95);
  box-shadow: 0px 15px 20px rgba(81, 83, 82, 0.4);

  &:hover {
    transform: perspective(1px) scale3d(1.044, 1.044, 1) translateZ(0) !important;
  }

  &:disabled {
    background: grey;
    cursor: not-allowed;
  }
`;


export { TableContainer, CenterDiv, HoverButton }

Enter fullscreen mode Exit fullscreen mode

Table.js

Now we're going to create the Table component, which will handle the retrieval and listing of Zoom Meeting Response data inside a table. To achieve this, add the following code to the Table.js file:

// Working Directory : frontend/src/components/pages/Home/Table/

import React from "react";

import DataTable from "react-data-table-component";

import { useResource } from "../../../hooks/useResource";

import { TableContainer } from "./TableComponents";

import { element } from "./dateTime";

const customStyles = {
  rows: {
    style: {
      minHeight: "35px",
    },
  },
  headCells: {
    style: {
      paddingLeft: "8px",
      paddingRight: "8px",
    },
  },
  cells: {
    style: {
      paddingLeft: "8px",
      paddingRight: "30px",
    },
  },
};


export default function Table({shouldFetch, onRequestClearData}) {

  const listmeetings = useResource("api/zoom/listmeetings");
  const newData = listmeetings?.resources?.meetings?.map((item) => ({
    keyField: item.id,
    topic: item.topic,
  }));

  const handleDelete = (e) => {
    console.log("handleDelete", e);
    alert(`Are you sure you want to delete meeting ${e} ?`);
  };


  const columns = [
    {
      selector: (row) => (
        <div onClick={(e) => e.stopPropagation()}>{row.topic}</div>
      ),
    },
    {
      selector: (row) => (
        <div onClick={(e) => e.stopPropagation()}>{row.keyField}</div>
      ),
    },
    {
      selector: (row) =>
        row.keyField ? (
          <div>
            <button value={row.keyField} onClick={() => handleDelete(row.keyField)}>
              <i class="material-icons large icon-blue"> delete_forever </i>
            </button>
          </div>
        ) : (
          <p>Loading</p>
        ),
    },
  ];


  return (
    <div style={{ maxWidth: "100vw", overflowX: "scroll" }}>
      <TableContainer>
        <div style={{ margin: "10px" }}>
          <DataTable
            title={element}
            columns={columns}
            data={shouldFetch ? newData : []}
            // progressPending={loading}
            customStyles={customStyles}
            pagination
          />
        </div>
      </TableContainer>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

Button Container

Now we're going to create the component that will hold all of the Application Buttons. In the src, run the following commands to change into Buttons directory and create the ButtonsContainer.js file:


// Working Directory: src/pages/Home/Table

cd ../Buttons/ && touch ButtonsContainer.js
Enter fullscreen mode Exit fullscreen mode

Make Button Container

To create the ButtonsContainer component, add the following code to the ButtonsContainer.js file:

// Working Directory : frontend/src/components/pages/Buttons
// File: ButtonsContainer.js

import React, { useState } from "react";
import styled from "styled-components";

import { BlueButton as ListMeetingsButton } from "./buttonComposition";
import { BlueButton as JoinMeetingButton } from "./buttonComposition";

import { NewMeetingButton } from "../Buttons/InstantMeetingButton";
import { JoinMeetingModal } from "../Dialogs/JoinMeetingModal";

const DivContainer = styled.div`
  display: grid;
  grid-template-columns: repeat(3, 2fr);
  grid-gap: 80px;
  padding: 1;
  width: 50%;
  height: 200px;
  flex-direction: row | row-reverse | column | column-reverse;
`;

export default function ButtonsContainer(props) {
  const [showModal, setShowModal] = useState(false);

  const openModal = () => {
    setShowModal(true);
  };

  // Handle data received from child component table switch button
  const handleListMeetingsClick = (event) => {
    event.preventDefault();
    try {
      props.onDataReceived(true);
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <>

        <DivContainer>
          <NewMeetingButton />

          <ListMeetingsButton text="list" label="List" onClick={handleListMeetingsClick} />

          <JoinMeetingButton text="add" label="Join" onClick={openModal} />

          {showModal ? <JoinMeetingModal setShowModal={setShowModal} /> : null}

        </DivContainer>

    </>
  );
}

Enter fullscreen mode Exit fullscreen mode

Create Home Page

Next we are going to create the Home component that will hold the Button Container and Table. In the src, run the following commands to change into Home directory and create the home.js file:

// Working DIR: frontend/src


cd pages/Home && touch Home.js
Enter fullscreen mode Exit fullscreen mode

Home.js

To create the Home component, add the following code to the home.js file:

// Working Directory : frontend/src/components/pages/Home
// File: Home.js

import React, { useState } from "react";
import ButtonsContainer from "./Buttons/ButtonsContainer";

import Table from "./Table/Table";

function Home() {
  const [dataFetched, setDataFetched] = useState(false);

  // Set data received from child component table switch button
  const handleDataReceived = (newData) => {
    console.log(" Handle Data received in Home.js", newData);
    setDataFetched(newData);
  };


  return (
    <>
      <div
        style={{
          display: "flex",
          margin: "auto",
          flexDirection: "row",
          height: "100vh",
          alignItems: "center",
          justifyContent: "center",
        }}
      >
        <div style={{ margin: "auto" }}>
          {" "}
          <ButtonsContainer onDataReceived={handleDataReceived} />
        </div>

        <div style={{ margin: "auto" }}> 
        {" "}

        <Table shouldFetch={dataFetched} onRequestClearData={ ()=> setDataFetched(false)} /> 
        </div>

      </div>
    </>
  );
}

export default Home;
Enter fullscreen mode Exit fullscreen mode

Update App.js

Finally, update the App.js to handling the routing between home and sdk page.

import React from "react";
import { Route, Routes } from "react-router-dom";

import Home from "./components/pages/Home/Home";
import ZoomMSDK from "./components/pages/ZoomMSDK/ZoomMSDK";

function App() {
  return (
    <div className="App">
      <Routes>
        <Route exact path="/" element={<Home />} />
        <Route path="/msdk" element={<ZoomMSDK />} />
      </Routes>
    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

Test Project

In the root, run the following command then navigate to your browser.

npm run dev
Enter fullscreen mode Exit fullscreen mode

You should see the following:

Image description


Conclusion

In the blog, you built a full stack React Application with Zoom Developer tools: Zoom Rest APIs and Zoom Web Meeting SDK. The app includes some commonly used features such as starting an instant meeting, making Zoom Rest APIs calls to retrieve users Zoom data, and joining Meetings with the click of a button. Hope this blog was helpful! If you're looking for help, know that you’re not alone: you can always come to the Zoom Developer Forum for help or try Developer Support.

💖 💪 🙅 🚩
justzoomit
just-zoomit

Posted on March 28, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related