Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PF-1391 - Adding breakout room example app #226

Merged
merged 36 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
5de2644
PF-1391 - Adding breakout room example app
fredcido Nov 15, 2023
147a0a9
PF-1391 - Creating breakout rooms
fredcido Nov 15, 2023
4218f51
PF-1391 - Initiate timer feature in breakout room
fredcido Nov 16, 2023
0eac2b6
PF-1391 - Timer UI
fredcido Nov 16, 2023
dfae4d3
PF-1391 - Adding TODO in styles
fredcido Nov 16, 2023
c80949c
PF-1391 - Implementing ticking time
fredcido Nov 17, 2023
fa90c8e
PF-1391 - Small adjustments in hooks
fredcido Nov 17, 2023
c297e7b
PF-1391 - Fixing session end hooks
fredcido Nov 20, 2023
248219b
Adding demo video
fredcido Nov 20, 2023
70d4831
PF-1391 - Iterating on README with folder structure
fredcido Nov 20, 2023
67b4d48
Remove video from selfie
fredcido Nov 20, 2023
8e2e56d
PF-1391 - Bumping @mirohq/[email protected]
fredcido Nov 20, 2023
815f67e
PF-1391 - Using multiple sessions
fredcido Nov 22, 2023
b3ccb05
UX iterations
fredcido Nov 27, 2023
f4b81e7
Adjusting styles
fredcido Nov 27, 2023
d056eb6
Use avatars
fredcido Nov 27, 2023
5e7a5db
Minor fixes
fredcido Nov 27, 2023
f177fc1
Update README.md
fredcido Nov 27, 2023
0483b91
Remove notes
fredcido Nov 27, 2023
8acd535
Merge branch 'PF-1391' of github.com:miroapp/app-examples into PF-1391
fredcido Nov 27, 2023
1faecbc
Update README.md
fredcido Nov 27, 2023
383c5b4
Update sdk types package
fredcido Nov 27, 2023
3c98937
PF-1391 - Update README with new folder structured
fredcido Nov 28, 2023
9bdd709
PF-1391 - Adding real-time events doc links
fredcido Nov 28, 2023
8369b71
Merge branch 'main' of github.com:miroapp/app-examples into PF-1391
fredcido Nov 28, 2023
8bff2dc
PF-1391 - Bumping @mirohq/sdk-types package to 2.9.10
fredcido Nov 28, 2023
efe1e9a
Update examples/breakout-rooms/src/components/BreakoutManager/Breakou…
fredcido Nov 29, 2023
52d38d6
PF-1391 - Styling using class names
fredcido Nov 29, 2023
b8f5c4f
PF-1391 - Reorganizing styles
fredcido Nov 29, 2023
6d9b63a
PF-1391 - Cleaning up imports
fredcido Nov 29, 2023
eb56091
PF-1391 - Treat facilitator differently
fredcido Nov 29, 2023
75caf1e
Update README.md with video and note about DS
fredcido Nov 29, 2023
8deaf27
PF-1391 - Bump SDK version
fredcido Nov 29, 2023
ad5aa1e
Merge branch 'PF-1391' of github.com:miroapp/app-examples into PF-1391
fredcido Nov 29, 2023
8bfb7bd
PF-1391 - Runs prettier
fredcido Nov 29, 2023
e2b1502
PF-1391 - Bump package
fredcido Nov 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ npx create-miro-app@latest
| [blob-maker](examples/blob-maker) | This example shows you how to create a drag and drop blobmaker using Miro's Web SDK. |
| [youtube-room](examples/youtube-room) | This example shows you how to sync a YouTube player across multiple users through Socket.IO. |
| [custom-actions](examples/custom-actions) | This example shows you how register [custom actions](https://developers.miro.com/docs/add-custom-actions-to-your-app) in the item context menu. |
| [breakout-rooms](examples/breakout-rooms) | This example shows you how use collaborative features (real-time storage, events, sessions, etc) |

<p>&nbsp;</p>

Expand Down
24 changes: 24 additions & 0 deletions examples/breakout-rooms/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js
.next

# testing
/coverage

# misc
.DS_Store
*.pem
.idea

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env
dist
5 changes: 5 additions & 0 deletions examples/breakout-rooms/APP_SUBMISSION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## Submission to Miro Marketplace

Congrats! You have finished building your app & you'd like to publish it for
users. You can submit your app on the
[Miro Marketplace](https://developers.miro.com/docs/submit-your-app) for review.
121 changes: 121 additions & 0 deletions examples/breakout-rooms/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Miro Breakout rooms

This example shows you how leverage collaborative and real-time features, including sessions and real-time events and storage.

# 👨🏻‍💻 App Demo

https://github.com/miroapp/app-examples/assets/7162412/e03987e3-f85b-48ab-86b8-f4314c3c5e76

# 📒 Table of Contents

- [Included Features](#features)
- [Tools and Technologies](#tools)
- [Prerequisites](#prerequisites)
- [Associated Developer Tutorial](#tutorial)
- [Run the app locally](#run)
- [Folder Structure](#folder)
- [License](#license)

# ⚙️ Included Features <a name="features"></a>

- [Miro Web SDK](https://developers.miro.com/docs/web-sdk-reference)
- [Collaborative sessions](https://developers.miro.com/docs/websdk-reference-session)
- [Attention Management](https://developers.miro.com/docs/websdk-reference-collaboration)
- [Real-time events](https://developers.miro.com/docs/websdk-reference-events)
- [Real-time storage](https://developers.miro.com/docs/websdk-reference-storage)

# 🛠️ Tools and Technologies <a name="tools"></a>

- [React](https://react.dev/)
- [TypeScript](https://www.typescriptlang.org/)
- [Vite](https://vitejs.dev/)
- [Miro Design System](https://www.npmjs.com/package/@mirohq/design-system)

**Note**: Miro Design System can be installed from [npmjs](https://www.npmjs.com/) but it is internally supported only, you can use this example as guidance, but the team is working on public documentation, but with no ETA. Feel free to use [Mirotone](https://www.mirotone.xyz/css) in the meanwhile.

# ✅ Prerequisites <a name="prerequisites"></a>

- You have a [Miro account](https://miro.com/signup/).
- You're [signed in to Miro](https://miro.com/login/).
- Your Miro account has a [Developer team](https://developers.miro.com/docs/create-a-developer-team).
- Your development environment includes [Node.js 14.13](https://nodejs.org/en/download) or a later version.
- All examples use `npm` as a package manager and `npx` as a package runner.

# 📖 Associated Developer Tutorial <a name="tutorial"></a>

> To view a more in depth developer tutorial
> of this app (including code explanations) see the [custom actions tutorial](https://developers.miro.com/docs/add-custom-actions-to-your-app) on Miro's Developer documentation.

# 🏃🏽‍♂️ Run the app locally <a name="run"></a>

1. Run `npm install` to install dependencies.
2. Run `npm start` to start developing. \
Your URL should be similar to this example:
```
http://localhost:3000
```
3. Open the [app manifest editor](https://developers.miro.com/docs/manually-create-an-app#step-2-configure-your-app-in-miro) by clicking **Edit in Manifest**. \
In the app manifest editor, configure the app as follows:

- [`sdkUri`](https://developers.miro.com/docs/app-manifest#sdkuri): assign `http://localhost:3000` as a value for this property. \
It defines the entry point of the app, and it corresponds to the URL of the server that the app runs on.
- [`scopes`](https://developers.miro.com/docs/app-manifest#scopes): add the permission scopes that users need to grant the app when they install it. \
To enable the app to read from and write to the board, add the following permissions:
- `boards:read`
- `boards:write`
- `identity:read`

#### Example of app yaml

```yaml
# See https://developers.miro.com/docs/app-manifest on how to use this
appName: Breakout rooms
sdkVersion: SDK_V2
sdkUri: http://localhost:3000
scopes:
- boards:read
- boards:write
- identity:read
```

4. Go back to your app home page, and under the `Permissions` section, you will see a blue button that says `Install app and get OAuth token`. Click that button. Then click on `Add` as shown in the video below. <b>In the video we install a different app, but the process is the same regardless of the app.</b>

> ⚠️ We recommend to install your app on a [developer team](https://developers.miro.com/docs/create-a-developer-team) while you are developing or testing apps.⚠️

https://github.com/miroapp/app-examples/assets/10428517/1e6862de-8617-46ef-b265-97ff1cbfe8bf

5. Go to your developer team, and open your boards.
6. Click on the app icon on the left sidebar.

# 🗂️ Folder structure <a name="folder"></a>

```
.
├── components
│ ├── Avatar
│ │ ├── Avatar.css
│ │ ├── Avatar.tsx
│ │ └── index.tsx
│ ├── BreakoutManager <-- Main React component displayed in the panel to facilitators
│ ├── BreakoutStarter <-- Component displayed when no rooms were configured
│ ├── RoomConfig <-- Component displayed for each configured room
│ ├── Timer <-- Timer controller component
│ ├── WaitingList <-- Component with unassigned users in the sessiin.
│ ├── WaitingRoom <-- Page displayed to participants while facilitator prepares the session.
│ ├── app.tsx <-- The app typescript entrypoint used in the panel.
│ ├── hooks.tsx <-- React hooks used in the app, including useCurrentUser, useBreakout, useTimer and some others.
│ ├── index.ts <-- The app main typescript entrypoint, rendered inside the headless iframe.
│ ├── types.ts <-- The app typescript types.
│ └── utils.ts <-- General code utilities, such as formatting and converting time in different units.
├── app.html <-- The app content displayed in the content when user clicks on the app icon on Miro boards.
├── index.html <-- The app entry point. This is the value you assign to 'sdkUri' in the app manifest file.

```

# 🫱🏻‍🫲🏽 Contributing <a name="contributing"></a>

If you want to contribute to this example, or any other Miro Open Source project, please review [Miro's contributing guide](https://github.com/miroapp/app-examples/blob/main/CONTRIBUTING.md).

# 🪪 License <a name="license"></a>

[MIT License](https://github.com/miroapp/app-examples/blob/main/LICENSE).
8 changes: 8 additions & 0 deletions examples/breakout-rooms/app-manifest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# See https://developers.miro.com/docs/app-manifest on how to use this
appName: Breakout rooms
sdkVersion: SDK_V2
sdkUri: http://localhost:3000
scopes:
- boards:read
- boards:write
- identity:read
15 changes: 15 additions & 0 deletions examples/breakout-rooms/app.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://miro.com/app/static/sdk/v2/miro.js"></script>
<link rel="stylesheet" href="/src/styles.css" />
<title>Miro - Breakout rooms</title>
</head>
<body>
<div id="root"></div>

<script type="module" src="/src/app.tsx"></script>
</body>
</html>
2 changes: 2 additions & 0 deletions examples/breakout-rooms/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// https://vitejs.dev/guide/features.html#typescript-compiler-options
/// <reference types="vite/client" />
12 changes: 12 additions & 0 deletions examples/breakout-rooms/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://miro.com/app/static/sdk/v2/miro.js"></script>
<title>Miro - Breakout rooms</title>
</head>
<body>
<script type="module" src="/src/index.ts"></script>
</body>
</html>
38 changes: 38 additions & 0 deletions examples/breakout-rooms/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "breakout-rooms",
"version": "0.0.1",
"license": "MIT",
"description": "This example shows you how leverage collaborative and real-time features, including sessions and real-time events and storage.",
"keywords": [
"Miro SDK",
"Vite",
"React",
"TypeSript",
"Collaborative",
"Breakout rooms",
"Real-time",
"Attention Management"
],
"scripts": {
"start": "vite",
"build": "vite build",
"serve": "vite preview"
},
"dependencies": {
"@mirohq/design-system": "^0.18.2",
"@stitches/react": "^1.2.8",
"classnames": "^2.3.2",
"mirotone": "5",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@mirohq/websdk-types": "latest",
"@types/node": "^18.8.2",
"@types/react": "^18.0.24",
"@types/react-dom": "^18.0.8",
"@vitejs/plugin-react": "^2.2.0",
"typescript": "4.9.5",
"vite": "3.0.3"
}
}
24 changes: 24 additions & 0 deletions examples/breakout-rooms/src/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"use client";

import * as React from "react";
import { useBreakout } from "./hooks";
import { BreakoutManager } from "./components/BreakoutManager";
import { WaitingRoom } from "./components/WaitingRoom/WaitingRoom";
import { createRoot } from "react-dom/client";
import { ErrorBoundary } from "./components/ErrorBoundary";

const App: React.FC = () => {
const { isFacilitator, breakout } = useBreakout();

const areYouReady = isFacilitator || !breakout;

return (
<ErrorBoundary>
{areYouReady ? <BreakoutManager /> : <WaitingRoom />}
</ErrorBoundary>
);
};

const container = document.getElementById("root")!;

Check warning on line 22 in examples/breakout-rooms/src/app.tsx

View workflow job for this annotation

GitHub Actions / Run linters

Forbidden non-null assertion
const root = createRoot(container);
root.render(<App />);
16 changes: 16 additions & 0 deletions examples/breakout-rooms/src/components/Avatar/Avatar.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.avatar {
border-radius: 100%;
flex-shrink: 0;
background: #817f99;
box-shadow: 0 0 0 6px var(--color, transparent);
outline: 4px solid #fff;
width: 2.2em;
height: 2.2em;
font-size: 14px;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
font-size: 12px;
font-weight: 600;
}
48 changes: 48 additions & 0 deletions examples/breakout-rooms/src/components/Avatar/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import * as React from "react";
import { OnlineUserInfo } from "@mirohq/websdk-types";
import { initials } from "../../utils";

export type Props = {
user: OnlineUserInfo;
color?: string;
};

import "./Avatar.css";

const colors = [
"var(--colors-blue-600)",
"var(--colors-green-600)",
"var(--colors-red-600)",
"var(--colors-yellow-600)",
];
function* colorGenerator(colors: string[]) {
let index = 0;
const totalColors = colors.length;

while (true) {
yield colors[index];
index = (index + 1) % totalColors;
}
}

const getNextColor = colorGenerator(colors);

const userColors = new Map<OnlineUserInfo["id"], string>();
const getUserColor = (user: OnlineUserInfo): string => {
let color = userColors.get(user.id);
if (!color) {
color = getNextColor.next().value ?? colors[0];
userColors.set(user.id, color);
}

return color;
};

export const Avatar: React.FC<Props> = ({ user }) => {
const style = { "--color": getUserColor(user) } as React.CSSProperties;
return (
<div className="avatar" key={user.id} style={style}>
{initials(user.name)}
</div>
);
};
1 change: 1 addition & 0 deletions examples/breakout-rooms/src/components/Avatar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./Avatar";
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.manager-container {
display: flex;
height: 100%;
flex-direction: column;
gap: 1em;
}

.validation-messages {
background: #f5f5f3;
padding: 1em;
}

.validation-messages .validatino-messages-title {
fredcido marked this conversation as resolved.
Show resolved Hide resolved
font-size: 1em;
font-weight: 600;
line-height: 1em;
margin: 0;
color: #656b81;
}

.validation-messages .validatino-messages-items {
fredcido marked this conversation as resolved.
Show resolved Hide resolved
font-size: 0.9em;
}

.toolbar {
display: flex;
flex-direction: column;
justify-content: center;
gap: 1em;
}

.toolbar button {
justify-content: center;
margin: 0;
width: 100%;
padding: 1em;
}
Loading
Loading