mirror of
https://github.com/xtr-dev/rondevu-demo.git
synced 2025-12-10 02:43:23 +00:00
Simplify demo: remove topics UI, ID-only connections
- Remove topic selection and peer discovery UI - Remove MethodSelector and TopicsList components - Simplify ConnectionForm to just take a connection ID - Update to use @xtr-dev/rondevu-client@0.3.2 - Demo version: 0.3.2 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
12
package-lock.json
generated
12
package-lock.json
generated
@@ -1,14 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "rondevu-demo",
|
"name": "rondevu-demo",
|
||||||
"version": "1.0.2",
|
"version": "0.3.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "rondevu-demo",
|
"name": "rondevu-demo",
|
||||||
"version": "1.0.2",
|
"version": "0.3.2",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@xtr-dev/rondevu-client": "^0.3.1",
|
"@xtr-dev/rondevu-client": "^0.3.2",
|
||||||
"@zxing/library": "^0.21.3",
|
"@zxing/library": "^0.21.3",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
@@ -1170,9 +1170,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@xtr-dev/rondevu-client": {
|
"node_modules/@xtr-dev/rondevu-client": {
|
||||||
"version": "0.3.1",
|
"version": "0.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/@xtr-dev/rondevu-client/-/rondevu-client-0.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@xtr-dev/rondevu-client/-/rondevu-client-0.3.2.tgz",
|
||||||
"integrity": "sha512-KVbssIVFNyIE4kw1Ygj36Ag29TW3CtNJXgrBRbyt/vNS8Phe0i61J0Z2isEzZs+rkuncaE6TWxNzU5CMljhI5g==",
|
"integrity": "sha512-qWQDP6L675bLksKrk8HYc1ZNoAe0X/1Fj92Lffh9HPHcoeME7ateXb0mD7KlPNNOem6u210q35FNTiJWuHEyuw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@zxing/library": {
|
"node_modules/@zxing/library": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "rondevu-demo",
|
"name": "rondevu-demo",
|
||||||
"version": "1.0.2",
|
"version": "0.3.2",
|
||||||
"description": "Demo application for Rondevu peer signaling and discovery",
|
"description": "Demo application for Rondevu peer signaling and discovery",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
"deploy": "npm run build && npx wrangler pages deploy dist --project-name=rondevu-demo"
|
"deploy": "npm run build && npx wrangler pages deploy dist --project-name=rondevu-demo"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@xtr-dev/rondevu-client": "^0.3.1",
|
"@xtr-dev/rondevu-client": "^0.3.2",
|
||||||
"@zxing/library": "^0.21.3",
|
"@zxing/library": "^0.21.3",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
|||||||
126
src/App.jsx
126
src/App.jsx
@@ -3,10 +3,8 @@ import { Rondevu } from '@xtr-dev/rondevu-client';
|
|||||||
import QRCode from 'qrcode';
|
import QRCode from 'qrcode';
|
||||||
import Header from './components/Header';
|
import Header from './components/Header';
|
||||||
import ActionSelector from './components/ActionSelector';
|
import ActionSelector from './components/ActionSelector';
|
||||||
import MethodSelector from './components/MethodSelector';
|
|
||||||
import ConnectionForm from './components/ConnectionForm';
|
import ConnectionForm from './components/ConnectionForm';
|
||||||
import ChatView from './components/ChatView';
|
import ChatView from './components/ChatView';
|
||||||
import TopicsList from './components/TopicsList';
|
|
||||||
|
|
||||||
const rdv = new Rondevu({
|
const rdv = new Rondevu({
|
||||||
baseUrl: 'https://api.ronde.vu',
|
baseUrl: 'https://api.ronde.vu',
|
||||||
@@ -35,17 +33,12 @@ function generateConnectionId() {
|
|||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
// Step-based state
|
// Step-based state
|
||||||
const [step, setStep] = useState(1); // 1: action, 2: method, 3: details, 4: connected
|
const [step, setStep] = useState(1); // 1: action, 2: details, 3: connected
|
||||||
const [action, setAction] = useState(null); // 'create', 'join', or 'scan'
|
const [action, setAction] = useState(null); // 'create' or 'connect'
|
||||||
const [method, setMethod] = useState(null); // 'topic', 'peer-id', 'connection-id'
|
|
||||||
const [qrCodeUrl, setQrCodeUrl] = useState('');
|
const [qrCodeUrl, setQrCodeUrl] = useState('');
|
||||||
|
|
||||||
// Connection state
|
// Connection state
|
||||||
const [topic, setTopic] = useState('');
|
|
||||||
const [connectionId, setConnectionId] = useState('');
|
const [connectionId, setConnectionId] = useState('');
|
||||||
const [peerId, setPeerId] = useState('');
|
|
||||||
const [topics, setTopics] = useState([]);
|
|
||||||
const [sessions, setSessions] = useState([]);
|
|
||||||
const [connectionStatus, setConnectionStatus] = useState('disconnected');
|
const [connectionStatus, setConnectionStatus] = useState('disconnected');
|
||||||
const [connectedPeer, setConnectedPeer] = useState(null);
|
const [connectedPeer, setConnectedPeer] = useState(null);
|
||||||
const [currentConnectionId, setCurrentConnectionId] = useState(null);
|
const [currentConnectionId, setCurrentConnectionId] = useState(null);
|
||||||
@@ -61,9 +54,6 @@ function App() {
|
|||||||
const [demoVersion, setDemoVersion] = useState('unknown');
|
const [demoVersion, setDemoVersion] = useState('unknown');
|
||||||
const [serverVersion, setServerVersion] = useState('unknown');
|
const [serverVersion, setServerVersion] = useState('unknown');
|
||||||
|
|
||||||
// Topics modal state
|
|
||||||
const [showTopicsList, setShowTopicsList] = useState(false);
|
|
||||||
|
|
||||||
const connectionRef = useRef(null);
|
const connectionRef = useRef(null);
|
||||||
const dataChannelRef = useRef(null);
|
const dataChannelRef = useRef(null);
|
||||||
const fileTransfersRef = useRef(new Map()); // Track ongoing file transfers
|
const fileTransfersRef = useRef(new Map()); // Track ongoing file transfers
|
||||||
@@ -71,7 +61,6 @@ function App() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
log('Demo initialized', 'info');
|
log('Demo initialized', 'info');
|
||||||
loadTopics();
|
|
||||||
loadVersions();
|
loadVersions();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -93,32 +82,13 @@ function App() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadTopics = async () => {
|
|
||||||
try {
|
|
||||||
const { topics } = await rdv.api.listTopics();
|
|
||||||
setTopics(topics);
|
|
||||||
} catch (error) {
|
|
||||||
log(`Error loading topics: ${error.message}`, 'error');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const discoverPeers = async (topicName) => {
|
|
||||||
try {
|
|
||||||
const { sessions: foundSessions } = await rdv.api.listSessions(topicName);
|
|
||||||
const otherSessions = foundSessions.filter(s => s.peerId !== rdv.peerId);
|
|
||||||
setSessions(otherSessions);
|
|
||||||
} catch (error) {
|
|
||||||
log(`Error discovering peers: ${error.message}`, 'error');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const setupConnection = (connection) => {
|
const setupConnection = (connection) => {
|
||||||
connectionRef.current = connection;
|
connectionRef.current = connection;
|
||||||
|
|
||||||
connection.on('connect', () => {
|
connection.on('connect', () => {
|
||||||
log('✅ Connected!', 'success');
|
log('✅ Connected!', 'success');
|
||||||
setConnectionStatus('connected');
|
setConnectionStatus('connected');
|
||||||
setStep(4);
|
setStep(3);
|
||||||
|
|
||||||
const channel = connection.dataChannel('chat');
|
const channel = connection.dataChannel('chat');
|
||||||
setupDataChannel(channel);
|
setupDataChannel(channel);
|
||||||
@@ -176,17 +146,10 @@ function App() {
|
|||||||
let connId;
|
let connId;
|
||||||
|
|
||||||
if (action === 'create') {
|
if (action === 'create') {
|
||||||
if (method === 'connection-id') {
|
connId = connectionId || generateConnectionId();
|
||||||
connId = connectionId || generateConnectionId();
|
connection = await rdv.create(connId);
|
||||||
connection = await rdv.create(connId, topic || 'default');
|
setCurrentConnectionId(connId);
|
||||||
setCurrentConnectionId(connId);
|
log(`Created connection: ${connId}`, 'success');
|
||||||
log(`Created connection: ${connId}`, 'success');
|
|
||||||
} else {
|
|
||||||
connId = generateConnectionId();
|
|
||||||
connection = await rdv.create(connId, topic);
|
|
||||||
setCurrentConnectionId(connId);
|
|
||||||
log(`Created connection: ${connId}`, 'success');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate QR code if creating a connection
|
// Generate QR code if creating a connection
|
||||||
try {
|
try {
|
||||||
@@ -204,18 +167,8 @@ function App() {
|
|||||||
log(`QR code generation error: ${err.message}`, 'error');
|
log(`QR code generation error: ${err.message}`, 'error');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (method === 'topic') {
|
connection = await rdv.connect(connectionId);
|
||||||
connection = await rdv.join(topic);
|
setCurrentConnectionId(connectionId);
|
||||||
setCurrentConnectionId(connection.id);
|
|
||||||
} else if (method === 'peer-id') {
|
|
||||||
connection = await rdv.join(topic, {
|
|
||||||
filter: (s) => s.peerId === peerId
|
|
||||||
});
|
|
||||||
setCurrentConnectionId(connection.id);
|
|
||||||
} else if (method === 'connection-id') {
|
|
||||||
connection = await rdv.connect(connectionId);
|
|
||||||
setCurrentConnectionId(connectionId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setConnectedPeer(connection.remotePeerId || 'Waiting...');
|
setConnectedPeer(connection.remotePeerId || 'Waiting...');
|
||||||
@@ -435,11 +388,7 @@ function App() {
|
|||||||
}
|
}
|
||||||
setStep(1);
|
setStep(1);
|
||||||
setAction(null);
|
setAction(null);
|
||||||
setMethod(null);
|
|
||||||
setTopic('');
|
|
||||||
setConnectionId('');
|
setConnectionId('');
|
||||||
setPeerId('');
|
|
||||||
setSessions([]);
|
|
||||||
setConnectionStatus('disconnected');
|
setConnectionStatus('disconnected');
|
||||||
setConnectedPeer(null);
|
setConnectedPeer(null);
|
||||||
setCurrentConnectionId(null);
|
setCurrentConnectionId(null);
|
||||||
@@ -452,9 +401,8 @@ function App() {
|
|||||||
|
|
||||||
const handleScanComplete = (scannedId) => {
|
const handleScanComplete = (scannedId) => {
|
||||||
setConnectionId(scannedId);
|
setConnectionId(scannedId);
|
||||||
setAction('join');
|
setAction('connect');
|
||||||
setMethod('connection-id');
|
setStep(2);
|
||||||
setStep(3);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleScanCancel = () => {
|
const handleScanCancel = () => {
|
||||||
@@ -482,39 +430,19 @@ function App() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{step === 2 && (
|
{step === 2 && (
|
||||||
<MethodSelector
|
<ConnectionForm
|
||||||
action={action}
|
action={action}
|
||||||
onSelectMethod={(m) => {
|
connectionId={connectionId}
|
||||||
setMethod(m);
|
setConnectionId={setConnectionId}
|
||||||
setStep(3);
|
connectionStatus={connectionStatus}
|
||||||
}}
|
qrCodeUrl={qrCodeUrl}
|
||||||
|
currentConnectionId={currentConnectionId}
|
||||||
|
onConnect={handleConnect}
|
||||||
onBack={() => setStep(1)}
|
onBack={() => setStep(1)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{step === 3 && (
|
{step === 3 && (
|
||||||
<ConnectionForm
|
|
||||||
action={action}
|
|
||||||
method={method}
|
|
||||||
topic={topic}
|
|
||||||
setTopic={setTopic}
|
|
||||||
connectionId={connectionId}
|
|
||||||
setConnectionId={setConnectionId}
|
|
||||||
peerId={peerId}
|
|
||||||
setPeerId={setPeerId}
|
|
||||||
topics={topics}
|
|
||||||
sessions={sessions}
|
|
||||||
connectionStatus={connectionStatus}
|
|
||||||
qrCodeUrl={qrCodeUrl}
|
|
||||||
currentConnectionId={currentConnectionId}
|
|
||||||
onConnect={handleConnect}
|
|
||||||
onBack={() => setStep(2)}
|
|
||||||
onTopicSelect={setTopic}
|
|
||||||
onDiscoverPeers={discoverPeers}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{step === 4 && (
|
|
||||||
<ChatView
|
<ChatView
|
||||||
connectedPeer={connectedPeer}
|
connectedPeer={connectedPeer}
|
||||||
currentConnectionId={currentConnectionId}
|
currentConnectionId={currentConnectionId}
|
||||||
@@ -533,24 +461,6 @@ function App() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="peer-id-badge">Your Peer ID: {rdv.peerId}</div>
|
<div className="peer-id-badge">Your Peer ID: {rdv.peerId}</div>
|
||||||
|
|
||||||
{/* Floating button to view topics */}
|
|
||||||
{step !== 4 && (
|
|
||||||
<button
|
|
||||||
className="view-topics-button"
|
|
||||||
onClick={() => setShowTopicsList(true)}
|
|
||||||
>
|
|
||||||
📊 View Topics
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Topics modal */}
|
|
||||||
{showTopicsList && (
|
|
||||||
<TopicsList
|
|
||||||
rdv={rdv}
|
|
||||||
onClose={() => setShowTopicsList(false)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer className="footer">
|
<footer className="footer">
|
||||||
|
|||||||
@@ -2,95 +2,31 @@ import QRCodeDisplay from './QRCodeDisplay';
|
|||||||
|
|
||||||
function ConnectionForm({
|
function ConnectionForm({
|
||||||
action,
|
action,
|
||||||
method,
|
|
||||||
topic,
|
|
||||||
setTopic,
|
|
||||||
connectionId,
|
connectionId,
|
||||||
setConnectionId,
|
setConnectionId,
|
||||||
peerId,
|
|
||||||
setPeerId,
|
|
||||||
topics,
|
|
||||||
sessions,
|
|
||||||
connectionStatus,
|
connectionStatus,
|
||||||
qrCodeUrl,
|
qrCodeUrl,
|
||||||
currentConnectionId,
|
currentConnectionId,
|
||||||
onConnect,
|
onConnect,
|
||||||
onBack,
|
onBack
|
||||||
onTopicSelect,
|
|
||||||
onDiscoverPeers
|
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="step-container">
|
<div className="step-container">
|
||||||
<h2>Enter Details</h2>
|
<h2>{action === 'create' ? 'Create Connection' : 'Join Connection'}</h2>
|
||||||
<div className="form-container">
|
<div className="form-container">
|
||||||
{(method === 'topic' || method === 'peer-id' || (method === 'connection-id' && action === 'create')) && (
|
<div className="form-group">
|
||||||
<div className="form-group">
|
<label>Connection ID {action === 'create' && '(optional)'}</label>
|
||||||
<label>Topic</label>
|
<input
|
||||||
<input
|
type="text"
|
||||||
type="text"
|
value={connectionId}
|
||||||
value={topic}
|
onChange={(e) => setConnectionId(e.target.value)}
|
||||||
onChange={(e) => setTopic(e.target.value)}
|
placeholder={action === 'create' ? 'Auto-generated if empty' : 'Enter connection ID'}
|
||||||
placeholder="e.g., game-room"
|
autoFocus={action === 'connect'}
|
||||||
autoFocus
|
/>
|
||||||
/>
|
{action === 'create' && !connectionId && (
|
||||||
{topics.length > 0 && (
|
<p className="help-text">Leave empty to auto-generate a random ID</p>
|
||||||
<div className="topic-list">
|
)}
|
||||||
{topics.map((t) => (
|
</div>
|
||||||
<button
|
|
||||||
key={t.topic}
|
|
||||||
className="topic-item"
|
|
||||||
onClick={() => {
|
|
||||||
onTopicSelect(t.topic);
|
|
||||||
if (method === 'peer-id') {
|
|
||||||
onDiscoverPeers(t.topic);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t.topic} <span className="peer-count">({t.count})</span>
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{method === 'peer-id' && (
|
|
||||||
<div className="form-group">
|
|
||||||
<label>Peer ID</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={peerId}
|
|
||||||
onChange={(e) => setPeerId(e.target.value)}
|
|
||||||
placeholder="e.g., player-123"
|
|
||||||
/>
|
|
||||||
{sessions.length > 0 && (
|
|
||||||
<div className="topic-list">
|
|
||||||
{sessions.map((s) => (
|
|
||||||
<button
|
|
||||||
key={s.code}
|
|
||||||
className="topic-item"
|
|
||||||
onClick={() => setPeerId(s.peerId)}
|
|
||||||
>
|
|
||||||
{s.peerId}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{method === 'connection-id' && (
|
|
||||||
<div className="form-group">
|
|
||||||
<label>Connection ID {action === 'create' && '(optional)'}</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={connectionId}
|
|
||||||
onChange={(e) => setConnectionId(e.target.value)}
|
|
||||||
placeholder={action === 'create' ? 'Auto-generated if empty' : 'e.g., meeting-123'}
|
|
||||||
autoFocus={action === 'join'}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="button-row">
|
<div className="button-row">
|
||||||
<button className="back-button" onClick={onBack}>← Back</button>
|
<button className="back-button" onClick={onBack}>← Back</button>
|
||||||
@@ -99,12 +35,10 @@ function ConnectionForm({
|
|||||||
onClick={onConnect}
|
onClick={onConnect}
|
||||||
disabled={
|
disabled={
|
||||||
connectionStatus === 'connecting' ||
|
connectionStatus === 'connecting' ||
|
||||||
(method === 'topic' && !topic) ||
|
(action === 'connect' && !connectionId)
|
||||||
(method === 'peer-id' && (!topic || !peerId)) ||
|
|
||||||
(method === 'connection-id' && action === 'join' && !connectionId)
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{connectionStatus === 'connecting' ? 'Connecting...' : 'Connect'}
|
{connectionStatus === 'connecting' ? 'Connecting...' : (action === 'create' ? 'Create' : 'Connect')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -162,6 +162,12 @@ body {
|
|||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.help-text {
|
||||||
|
margin-top: 8px;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: #6c757d;
|
||||||
|
}
|
||||||
|
|
||||||
input[type="text"] {
|
input[type="text"] {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
|
|||||||
Reference in New Issue
Block a user