import React, { useCallback, useEffect, useRef, useState, createContext, useContext, } from "react"; import * as sdk from "matrix-js-sdk"; import "./App.css"; const ClientContext = createContext(); export default function App() { const { protocol, host } = window.location; // Assume homeserver is hosted on same domain (proxied in development by vite) const homeserverUrl = `${protocol}//${host}`; const { loading, authenticated, error, client, login, register } = useClient(homeserverUrl); const [roomId, setRoomId] = useState(); return (
{error &&

{error.message}

} {loading ? (

Loading...

) : ( <> {!authenticated && } {!authenticated && } {authenticated && !roomId && ( )} {authenticated && roomId && } )}
); } function useClient(homeserverUrl) { const [authenticated, setAuthenticated] = useState(false); const [client, setClient] = useState(); const [error, setError] = useState(); useEffect(() => { async function restoreClient() { try { const authStore = localStorage.getItem("matrix-auth-store"); if (authStore) { const { user_id, device_id, access_token } = JSON.parse(authStore); const client = sdk.createClient({ baseUrl: homeserverUrl, accessToken: access_token, userId: user_id, deviceId: device_id, }); await client.startClient(); setAuthenticated(true); setClient(client); } } catch (err) { console.error(err); localStorage.removeItem("matrix-auth-store"); setAuthenticated(false); setError(err); } } restoreClient(); }, []); const login = useCallback(async (username, password) => { try { setError(undefined); const registrationClient = sdk.createClient(homeserverUrl); const { user_id, device_id, access_token } = await registrationClient.loginWithPassword(username, password); const client = sdk.createClient({ baseUrl: homeserverUrl, accessToken: access_token, userId: user_id, deviceId: device_id, }); await client.startClient(); localStorage.setItem( "matrix-auth-store", JSON.stringify({ user_id, device_id, access_token }) ); setAuthenticated(true); setClient(client); } catch (err) { console.error(err); localStorage.removeItem("matrix-auth-store"); setAuthenticated(false); setError(err); } }, []); const register = useCallback( async (username, password) => { try { setError(undefined); const registrationClient = sdk.createClient(homeserverUrl); const { user_id, device_id, access_token } = await registrationClient.register(username, password, null, { type: "m.login.dummy", }); const client = sdk.createClient({ baseUrl: homeserverUrl, accessToken: access_token, userId: user_id, deviceId: device_id, }); await client.startClient(); localStorage.setItem( "matrix-auth-store", JSON.stringify({ user_id, device_id, access_token }) ); setAuthenticated(true); setClient(client); } catch (err) { localStorage.removeItem("matrix-auth-store"); setAuthenticated(false); setError(err); } }, [client, homeserverUrl] ); return { authenticated, client, error, login, register }; } function Register({ onRegister }) { const usernameRef = useRef(); const passwordRef = useRef(); const onSubmit = useCallback((e) => { e.preventDefault(); onRegister(usernameRef.current.value, passwordRef.current.value); }); return (
); } function Login({ onLogin }) { const usernameRef = useRef(); const passwordRef = useRef(); const onSubmit = useCallback((e) => { e.preventDefault(); onLogin(usernameRef.current.value, passwordRef.current.value); }); return (
); } function JoinOrCreateRoom({ onSetRoomId }) { const client = useContext(ClientContext); const roomNameRef = useRef(); const roomIdRef = useRef(); const [createRoomError, setCreateRoomError] = useState(); const [joinRoomError, setJoinRoomError] = useState(); const onCreateRoom = useCallback( (e) => { e.preventDefault(); setCreateRoomError(undefined); client .createRoom({ visibility: "private", name: roomNameRef.current.value, }) .then(({ room_id }) => { onSetRoomId(room_id); }) .catch(setCreateRoomError); }, [client] ); const onJoinRoom = useCallback( (e) => { e.preventDefault(); setJoinRoomError(undefined); client .joinRoom(roomIdRef.current.value) .then(({ roomId }) => { onSetRoomId(roomId); }) .catch(setJoinRoomError); }, [client] ); return (

Create New Room

{createRoomError &&

{createRoomError.message}

}

Join Existing Room

{joinRoomError &&

{joinRoomError.message}

}
); } function useVideoRoom(roomId, timeout = 5000) { const client = useContext(ClientContext); const [room, setRoom] = useState(); const [error, setError] = useState(); useEffect(() => { setRoom(undefined); let initialRoom = client.getRoom(roomId); if (initialRoom) { setRoom(initialRoom); return; } let timeoutId; function roomCallback(room) { if (room && room.roomId === roomId) { clearTimeout(timeoutId); client.removeListener("Room", roomCallback); setRoom(room); } } client.on("Room", roomCallback); timeoutId = setTimeout(() => { setError(new Error("Room could not be found.")); client.removeListener("Room", roomCallback); }, timeout); return () => { client.removeListener("Room", roomCallback); clearTimeout(timeoutId); }; }, [roomId]); return { room, error }; } function Room({ roomId }) { const { room, error } = useVideoRoom(roomId); useEffect(() => { if (room) { console.log(room); } }, [room]); return (

{roomId}

{!error && !room &&

Loading room...

} {error &&

{error.message}

}
); }