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 (
);
}
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}
}
);
}