Skip to content
This repository was archived by the owner on Oct 30, 2025. It is now read-only.

Commit 1fef708

Browse files
authored
Merge pull request #48 from dyte-io/feat/back-to-back-meetings-sample
feat(back-to-back-meetings-sample): added a new sample to test back to back meetings
2 parents 891c793 + 5fdb7ae commit 1fef708

File tree

35 files changed

+822
-64
lines changed

35 files changed

+822
-64
lines changed

index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ <h1>Cloudflare Realtime Kit React Samples</h1>
8888
<li><a href="/samples/default-meeting-ui/dist">Default Meeting UI</a></li>
8989
<li><a href="/samples/facetime/dist">Facetime</a></li>
9090
<li><a href="/samples/live-auction/dist">Live Auction</a></li>
91+
<li><a href="/samples/back-to-back-meetings/dist">Back-to-Back Meetings</a></li>
9192
<li><a href="/samples/multi-meeting/dist">Multiple Meeting UI</a></li>
9293
<li><a href="/samples/multi-meeting-custom/dist">Multiple Meeting UI with Custom UI</a></li>
9394
<li><a href="/samples/screenshare-focused-ui-with-custom-addons/dist">Screenshare Focused UI with Custom Addons</a></li>

samples/active-speaker-ui/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
"preview": "vite preview"
1010
},
1111
"dependencies": {
12-
"@cloudflare/realtimekit": "^1.1.5",
13-
"@cloudflare/realtimekit-react": "^1.1.5",
14-
"@cloudflare/realtimekit-ui": "^1.0.4",
15-
"@cloudflare/realtimekit-react-ui": "^1.0.4",
12+
"@cloudflare/realtimekit": "^1.1.6",
13+
"@cloudflare/realtimekit-react": "^1.1.6",
14+
"@cloudflare/realtimekit-ui": "^1.0.5",
15+
"@cloudflare/realtimekit-react-ui": "^1.0.5",
1616
"@cloudflare/realtimekit-ui-addons": "^0.0.4",
1717
"clsx": "^2.1.0",
1818
"react": "^18.2.0",

samples/async-video-survey/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
"preview": "vite preview"
1010
},
1111
"dependencies": {
12-
"@cloudflare/realtimekit": "^1.1.5",
13-
"@cloudflare/realtimekit-react": "^1.1.5",
14-
"@cloudflare/realtimekit-ui": "^1.0.4",
15-
"@cloudflare/realtimekit-react-ui": "^1.0.4",
12+
"@cloudflare/realtimekit": "^1.1.6",
13+
"@cloudflare/realtimekit-react": "^1.1.6",
14+
"@cloudflare/realtimekit-ui": "^1.0.5",
15+
"@cloudflare/realtimekit-react-ui": "^1.0.5",
1616
"@cloudflare/realtimekit-ui-addons": "^0.0.4",
1717
"autoprefixer": "^10.4.15",
1818
"postcss": "^8.4.29",

samples/audio-room/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
"preview": "vite preview"
1010
},
1111
"dependencies": {
12-
"@cloudflare/realtimekit": "^1.1.5",
13-
"@cloudflare/realtimekit-react": "^1.1.5",
14-
"@cloudflare/realtimekit-ui": "^1.0.4",
15-
"@cloudflare/realtimekit-react-ui": "^1.0.4",
12+
"@cloudflare/realtimekit": "^1.1.6",
13+
"@cloudflare/realtimekit-react": "^1.1.6",
14+
"@cloudflare/realtimekit-ui": "^1.0.5",
15+
"@cloudflare/realtimekit-react-ui": "^1.0.5",
1616
"@cloudflare/realtimekit-ui-addons": "^0.0.4",
1717
"clsx": "^1.2.1",
1818
"good-grid": "^0.3.0",
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Back to Back Meetings
2+
3+
A sample designed for continuous meeting workflows where participants need to transition seamlessly from one meeting to the next without interruption. Perfect for scenarios like back-to-back appointments, consecutive interviews, or sequential consultations.
4+
5+
## Features
6+
7+
- **Continuous Meeting Flow**: Automatically transitions from one meeting to the next
8+
- **Single Meeting Display**: Focus on one meeting at a time
9+
- **Zero Manual Joins**: No need to manually join meetings - transitions happen automatically
10+
- **Session Complete Screen**: Shows completion message with option to restart the meeting cycle
11+
- **Room Left Event Integration**: Uses `meeting.self.on('roomLeft')` to trigger automatic transitions
12+
- **State Isolation**: Each meeting maintains its own isolated state using Zustand stores
13+
- **UI Addons**: Includes video backgrounds, hand raise, and host controls
14+
15+
## How It Works
16+
17+
1. **First Meeting**: Automatically begins when the first meeting token is provided
18+
2. **Seamless Transition**: When one meeting ends, the next meeting automatically starts
19+
3. **Continuous Workflow**: Designed for scenarios requiring uninterrupted meeting sequences
20+
4. **Session Complete**: After all scheduled meetings, shows completion screen with restart option
21+
22+
## Usage
23+
24+
Pass auth tokens via URL parameters:
25+
```
26+
?authToken1=<first-meeting-token>&authToken2=<second-meeting-token>
27+
```
28+
29+
### Parameters
30+
- `authToken1` (required): Token for the first meeting
31+
- `authToken2` (optional): Token for the second meeting
32+
33+
## Architecture
34+
35+
- **App.tsx**: Main component handling meeting state and transitions
36+
- **Meeting.tsx**: Individual meeting component with addons and event handling
37+
- **store.ts**: Zustand-based state management with per-meeting isolation
38+
- **components/**: Custom RTK UI components for meeting display
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Back to Back Meetings</title>
8+
</head>
9+
<body>
10+
<div id="root"></div>
11+
<script type="module" src="/src/main.tsx"></script>
12+
</body>
13+
</html>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "back-to-back-meetings",
3+
"private": true,
4+
"version": "0.0.0",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "tsc && vite build",
9+
"preview": "vite preview"
10+
},
11+
"dependencies": {
12+
"@cloudflare/realtimekit-react": "^1.1.6",
13+
"@cloudflare/realtimekit-react-ui": "^1.0.5",
14+
"@cloudflare/realtimekit-ui-addons": "^0.0.4",
15+
"react": "^18.2.0",
16+
"react-dom": "^18.2.0",
17+
"zustand": "^4.4.1",
18+
"@cloudflare/realtimekit": "^1.1.6",
19+
"@cloudflare/realtimekit-ui": "^1.0.5"
20+
},
21+
"devDependencies": {
22+
"@types/react": "^18.2.15",
23+
"@types/react-dom": "^18.2.7",
24+
"@vitejs/plugin-react": "^4.0.3",
25+
"autoprefixer": "^10.4.14",
26+
"postcss": "^8.4.27",
27+
"tailwindcss": "^3.3.3",
28+
"typescript": "^5.0.2",
29+
"vite": "^4.4.5"
30+
}
31+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default {
2+
plugins: {
3+
tailwindcss: {},
4+
autoprefixer: {},
5+
},
6+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import { useState, useEffect } from 'react';
2+
import { Meeting } from './Meeting';
3+
4+
function App() {
5+
const url = new URL(window.location.href);
6+
const urlAuthToken1 = url.searchParams.get('authToken1');
7+
const urlAuthToken2 = url.searchParams.get('authToken2');
8+
const baseURI = url.searchParams.get('baseURI') || 'dyte.io';
9+
10+
const [authToken1] = useState(urlAuthToken1 || '');
11+
const [authToken2] = useState(urlAuthToken2 || '');
12+
const [currentMeeting, setCurrentMeeting] = useState<1 | 2 | null>(null);
13+
const [demoComplete, setDemoComplete] = useState(false);
14+
15+
// Auto-initialize first meeting if token is available
16+
useEffect(() => {
17+
if (authToken1 && !currentMeeting) {
18+
setCurrentMeeting(1);
19+
}
20+
}, [authToken1, currentMeeting]);
21+
22+
const handleMeetingLeft = () => {
23+
console.log('Meeting left, automatically switching to next meeting');
24+
25+
if (currentMeeting === 1 && authToken2) {
26+
// Switch from Meeting 1 to Meeting 2
27+
setCurrentMeeting(2);
28+
} else {
29+
// Demo complete - either leaving Meeting 2 or no next meeting token
30+
setCurrentMeeting(null);
31+
setDemoComplete(true);
32+
}
33+
};
34+
35+
const getCurrentAuthToken = () => {
36+
if (currentMeeting === 1) return authToken1;
37+
if (currentMeeting === 2) return authToken2;
38+
return '';
39+
};
40+
return (
41+
<div className="w-full h-screen bg-gray-100">
42+
{/* Header */}
43+
<div className="bg-white shadow-sm border-b px-6 py-4">
44+
<div className="flex items-center justify-between">
45+
<h1 className="text-2xl font-bold text-gray-900">Back to Back Meetings</h1>
46+
<div className="flex items-center space-x-4">
47+
{currentMeeting && (
48+
<span className="px-3 py-1 bg-blue-100 text-blue-800 rounded-full text-sm font-medium">
49+
Meeting {currentMeeting} Active
50+
</span>
51+
)}
52+
53+
</div>
54+
</div>
55+
</div>
56+
57+
{/* Meeting Container */}
58+
<div className="flex-1" style={{ height: 'calc(100vh - 80px)' }}>
59+
{!authToken1 && !authToken2 ? (
60+
<div className="flex items-center justify-center h-full">
61+
<div className="text-center max-w-2xl mx-auto px-6">
62+
<h2 className="text-2xl font-semibold text-gray-700 mb-6">
63+
Welcome to Back-to-Back Meetings
64+
</h2>
65+
<div className="bg-red-50 border border-red-200 rounded-lg p-6 mb-6">
66+
<h3 className="text-lg font-medium text-red-900 mb-3">No Auth Tokens Provided</h3>
67+
<p className="text-red-800 mb-3">
68+
Please provide authToken1 and/or authToken2 in the URL parameters.
69+
</p>
70+
<p className="text-sm text-red-600">
71+
<strong>Example:</strong> ?authToken1=token1&authToken2=token2
72+
</p>
73+
</div>
74+
<div className="bg-blue-50 border border-blue-200 rounded-lg p-6 mb-6">
75+
<h3 className="text-lg font-medium text-blue-900 mb-3">How it works:</h3>
76+
<div className="text-left space-y-3 text-blue-800">
77+
<div className="flex items-start space-x-3">
78+
<span className="flex-shrink-0 w-6 h-6 bg-blue-600 text-white rounded-full flex items-center justify-center text-sm font-medium">1</span>
79+
<p>Meeting 1 will start automatically when you provide authToken1</p>
80+
</div>
81+
<div className="flex items-start space-x-3">
82+
<span className="flex-shrink-0 w-6 h-6 bg-blue-600 text-white rounded-full flex items-center justify-center text-sm font-medium">2</span>
83+
<p><strong>To switch to Meeting 2:</strong> Use the "Leave" button in the bottom control bar</p>
84+
</div>
85+
<div className="flex items-start space-x-3">
86+
<span className="flex-shrink-0 w-6 h-6 bg-blue-600 text-white rounded-full flex items-center justify-center text-sm font-medium">3</span>
87+
<p>Meeting 2 will automatically start when you leave Meeting 1 (if authToken2 is provided)</p>
88+
</div>
89+
</div>
90+
</div>
91+
</div>
92+
</div>
93+
) : demoComplete ? (
94+
<div className="flex items-center justify-center h-full">
95+
<div className="text-center max-w-2xl mx-auto px-6">
96+
<h2 className="text-2xl font-semibold text-green-700 mb-6">
97+
🎉 Demo Complete!
98+
</h2>
99+
<div className="bg-green-50 border border-green-200 rounded-lg p-6 mb-6">
100+
<h3 className="text-lg font-medium text-green-900 mb-3">Back-to-Back Meetings Demo Finished</h3>
101+
<p className="text-green-800 mb-4">
102+
You have successfully experienced the back-to-back meetings functionality by switching between Meeting 1 and Meeting 2.
103+
</p>
104+
<p className="text-green-700">
105+
To try the demo again, please reload the page.
106+
</p>
107+
</div>
108+
<button
109+
onClick={() => window.location.reload()}
110+
className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-medium"
111+
>
112+
Reload Page to Try Again
113+
</button>
114+
</div>
115+
</div>
116+
) : (
117+
<div style={{ height: '90vh', width: '100%' }}>
118+
<Meeting
119+
authToken={getCurrentAuthToken()}
120+
baseURI={baseURI}
121+
meetingIdentifier={`meeting-${currentMeeting}`}
122+
onMeetingLeft={handleMeetingLeft}
123+
/>
124+
</div>
125+
)}
126+
</div>
127+
</div>
128+
);
129+
}
130+
131+
export default App;

0 commit comments

Comments
 (0)