diff --git a/src/profile/ProfileModal.jsx b/src/profile/ProfileModal.tsx similarity index 83% rename from src/profile/ProfileModal.jsx rename to src/profile/ProfileModal.tsx index b0dee0e..26b99e9 100644 --- a/src/profile/ProfileModal.jsx +++ b/src/profile/ProfileModal.tsx @@ -15,6 +15,8 @@ limitations under the License. */ import React, { useCallback, useEffect, useState } from "react"; +import { MatrixClient } from "matrix-js-sdk"; + import { Button } from "../button"; import { useProfile } from "./useProfile"; import { FieldRow, InputField, ErrorMessage } from "../input/Input"; @@ -22,7 +24,12 @@ import { Modal, ModalContent } from "../Modal"; import { AvatarInputField } from "../input/AvatarInputField"; import styles from "./ProfileModal.module.css"; -export function ProfileModal({ client, ...rest }) { +interface Props { + client: MatrixClient; + onClose: () => {}; + [rest: string]: unknown; +} +export function ProfileModal({ client, ...rest }: Props) { const { onClose } = rest; const { success, @@ -50,13 +57,20 @@ export function ProfileModal({ client, ...rest }) { (e) => { e.preventDefault(); const data = new FormData(e.target); - const displayName = data.get("displayName"); - const avatar = data.get("avatar"); + const displayNameDataEntry = data.get("displayName"); + const avatar: File | string = data.get("avatar"); + + const avatarSize = + typeof avatar == "string" ? avatar.length : avatar.size; + const displayName = + typeof displayNameDataEntry == "string" + ? displayNameDataEntry + : displayNameDataEntry.name; saveProfile({ displayName, - avatar: avatar && avatar.size > 0 ? avatar : undefined, - removeAvatar: removeAvatar && (!avatar || avatar.size === 0), + avatar: avatar && avatarSize > 0 ? avatar : undefined, + removeAvatar: removeAvatar && (!avatar || avatarSize === 0), }); }, [saveProfile, removeAvatar] diff --git a/src/profile/useProfile.js b/src/profile/useProfile.ts similarity index 66% rename from src/profile/useProfile.js rename to src/profile/useProfile.ts index 2207dde..4eadcd8 100644 --- a/src/profile/useProfile.js +++ b/src/profile/useProfile.ts @@ -14,11 +14,36 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { + FileType, + MatrixClient, + MatrixEvent, + User, + UserEvent, +} from "matrix-js-sdk"; import { useState, useCallback, useEffect } from "react"; -export function useProfile(client) { +interface ProfileLoadState { + success?: boolean; + loading?: boolean; + displayName: string; + avatarUrl: string; + error?: Error; +} + +type ProfileSaveCallback = ({ + displayName, + avatar, + removeAvatar, +}: { + displayName: string; + avatar: FileType; + removeAvatar: boolean; +}) => Promise; + +export function useProfile(client: MatrixClient) { const [{ loading, displayName, avatarUrl, error, success }, setState] = - useState(() => { + useState(() => { const user = client?.getUser(client.getUserId()); return { @@ -31,7 +56,10 @@ export function useProfile(client) { }); useEffect(() => { - const onChangeUser = (_event, { displayName, avatarUrl }) => { + const onChangeUser = ( + _event: MatrixEvent, + { displayName, avatarUrl }: User + ) => { setState({ success: false, loading: false, @@ -41,24 +69,24 @@ export function useProfile(client) { }); }; - let user; + let user: User; if (client) { const userId = client.getUserId(); user = client.getUser(userId); - user.on("User.displayName", onChangeUser); - user.on("User.avatarUrl", onChangeUser); + user.on(UserEvent.DisplayName, onChangeUser); + user.on(UserEvent.AvatarUrl, onChangeUser); } return () => { if (user) { - user.removeListener("User.displayName", onChangeUser); - user.removeListener("User.avatarUrl", onChangeUser); + user.removeListener(UserEvent.DisplayName, onChangeUser); + user.removeListener(UserEvent.AvatarUrl, onChangeUser); } }; }, [client]); - const saveProfile = useCallback( + const saveProfile = useCallback( async ({ displayName, avatar, removeAvatar }) => { if (client) { setState((prev) => ({ @@ -71,7 +99,7 @@ export function useProfile(client) { try { await client.setDisplayName(displayName); - let mxcAvatarUrl; + let mxcAvatarUrl: string; if (removeAvatar) { await client.setAvatarUrl(""); @@ -87,11 +115,11 @@ export function useProfile(client) { loading: false, success: true, })); - } catch (error) { + } catch (error: unknown) { setState((prev) => ({ ...prev, loading: false, - error, + error: error instanceof Error ? error : Error(error as string), success: false, })); } @@ -102,5 +130,12 @@ export function useProfile(client) { [client] ); - return { loading, error, displayName, avatarUrl, saveProfile, success }; + return { + loading, + error, + displayName, + avatarUrl, + saveProfile, + success, + }; }