diff --git a/src/ConferenceCallManagerHooks.jsx b/src/ConferenceCallManagerHooks.jsx
index d506780..b559a25 100644
--- a/src/ConferenceCallManagerHooks.jsx
+++ b/src/ConferenceCallManagerHooks.jsx
@@ -612,17 +612,35 @@ export function getRoomUrl(roomId) {
}
}
-export function useDisplayName(client) {
- const [{ loading, displayName, error, success }, setState] = useState(() => ({
- success: false,
- loading: false,
- displayName: client?.getUser(client.getUserId())?.displayName,
- error: null,
- }));
+function getAvatarUrl(client, mxcUrl, avatarSize = 96) {
+ const width = Math.floor(avatarSize * window.devicePixelRatio);
+ const height = Math.floor(avatarSize * window.devicePixelRatio);
+ return mxcUrl && client.mxcUrlToHttp(mxcUrl, width, height, "crop");
+}
+
+export function useProfile(client) {
+ const [{ loading, displayName, avatarUrl, error, success }, setState] =
+ useState(() => {
+ const user = client?.getUser(client.getUserId());
+
+ return {
+ success: false,
+ loading: false,
+ displayName: user?.displayName,
+ avatarUrl: user && client && getAvatarUrl(client, user.avatarUrl),
+ error: null,
+ };
+ });
useEffect(() => {
- const onChangeDisplayName = (_event, { displayName }) => {
- setState({ success: false, loading: false, displayName, error: null });
+ const onChangeUser = (_event, { displayName, avatarUrl }) => {
+ setState({
+ success: false,
+ loading: false,
+ displayName,
+ avatarUrl: getAvatarUrl(client, avatarUrl),
+ error: null,
+ });
};
let user;
@@ -630,18 +648,20 @@ export function useDisplayName(client) {
if (client) {
const userId = client.getUserId();
user = client.getUser(userId);
- user.on("User.displayName", onChangeDisplayName);
+ user.on("User.displayName", onChangeUser);
+ user.on("User.avatarUrl", onChangeUser);
}
return () => {
if (user) {
- user.removeListener("User.displayName", onChangeDisplayName);
+ user.removeListener("User.displayName", onChangeUser);
+ user.removeListener("User.avatarUrl", onChangeUser);
}
};
}, [client]);
- const setDisplayName = useCallback(
- (displayName) => {
+ const saveProfile = useCallback(
+ async ({ displayName, avatar }) => {
if (client) {
setState((prev) => ({
...prev,
@@ -650,30 +670,33 @@ export function useDisplayName(client) {
success: false,
}));
- client
- .setDisplayName(displayName)
- .then(() => {
- setState((prev) => ({
- ...prev,
- displayName,
- loading: false,
- success: true,
- }));
- })
- .catch((error) => {
- setState((prev) => ({
- ...prev,
- loading: false,
- error,
- success: false,
- }));
- });
+ try {
+ await client.setDisplayName(displayName);
+
+ const url = await client.uploadContent(avatar);
+ await client.setAvatarUrl(url);
+
+ setState((prev) => ({
+ ...prev,
+ displayName,
+ avatarUrl: getAvatarUrl(client, url),
+ loading: false,
+ success: true,
+ }));
+ } catch (error) {
+ setState((prev) => ({
+ ...prev,
+ loading: false,
+ error,
+ success: false,
+ }));
+ }
} else {
- console.error("Client not initialized before calling setDisplayName");
+ console.error("Client not initialized before calling saveProfile");
}
},
[client]
);
- return { loading, error, displayName, setDisplayName, success };
+ return { loading, error, displayName, avatarUrl, saveProfile, success };
}
diff --git a/src/ProfileModal.jsx b/src/ProfileModal.jsx
index 1517672..3e86e86 100644
--- a/src/ProfileModal.jsx
+++ b/src/ProfileModal.jsx
@@ -1,6 +1,6 @@
import React, { useCallback, useEffect, useState } from "react";
import { Button } from "./button";
-import { useDisplayName } from "./ConferenceCallManagerHooks";
+import { useProfile } from "./ConferenceCallManagerHooks";
import { FieldRow, InputField, ErrorMessage } from "./Input";
import { Modal, ModalContent } from "./Modal";
@@ -11,8 +11,8 @@ export function ProfileModal({ client, ...rest }) {
error,
loading,
displayName: initialDisplayName,
- setDisplayName: submitDisplayName,
- } = useDisplayName(client);
+ saveProfile,
+ } = useProfile(client);
const [displayName, setDisplayName] = useState(initialDisplayName || "");
const onChangeDisplayName = useCallback(
@@ -27,10 +27,14 @@ export function ProfileModal({ client, ...rest }) {
e.preventDefault();
const data = new FormData(e.target);
const displayName = data.get("displayName");
- console.log(displayName);
- submitDisplayName(displayName);
+ const avatar = data.get("avatar");
+
+ saveProfile({
+ displayName,
+ avatar,
+ });
},
- [setDisplayName]
+ [saveProfile]
);
useEffect(() => {
@@ -56,6 +60,9 @@ export function ProfileModal({ client, ...rest }) {
onChange={onChangeDisplayName}
/>
+
+
+
{error && (
{error.message}
diff --git a/src/UserMenu.jsx b/src/UserMenu.jsx
index 9f99bd0..f67742a 100644
--- a/src/UserMenu.jsx
+++ b/src/UserMenu.jsx
@@ -8,10 +8,11 @@ import styles from "./UserMenu.module.css";
import { Item } from "@react-stately/collections";
import { Menu } from "./Menu";
import { useHistory, useLocation } from "react-router-dom";
-import { useClient, useDisplayName } from "./ConferenceCallManagerHooks";
+import { useClient, useProfile } from "./ConferenceCallManagerHooks";
import { useModalTriggerState } from "./Modal";
import { ProfileModal } from "./ProfileModal";
import { Tooltip, TooltipTrigger } from "./Tooltip";
+import { Avatar } from "./Avatar";
export function UserMenu({ disableLogout }) {
const location = useLocation();
@@ -24,7 +25,7 @@ export function UserMenu({ disableLogout }) {
userName,
client,
} = useClient();
- const { displayName } = useDisplayName(client);
+ const { displayName, avatarUrl } = useProfile(client);
const { modalState, modalProps } = useModalTriggerState();
const onAction = useCallback(
@@ -87,7 +88,16 @@ export function UserMenu({ disableLogout }) {
{(props) => (