diff --git a/web/src/ui/rightpanel/RightPanel.css b/web/src/ui/rightpanel/RightPanel.css index 5b08a9b..5ee2db6 100644 --- a/web/src/ui/rightpanel/RightPanel.css +++ b/web/src/ui/rightpanel/RightPanel.css @@ -119,7 +119,7 @@ div.right-panel-content.user { justify-content: left; justify-items: left; gap: .5rem; - + } div.presencesetter > button { diff --git a/web/src/ui/rightpanel/UserInfo.tsx b/web/src/ui/rightpanel/UserInfo.tsx index 428010b..46e7581 100644 --- a/web/src/ui/rightpanel/UserInfo.tsx +++ b/web/src/ui/rightpanel/UserInfo.tsx @@ -17,7 +17,7 @@ import { use, useCallback, useEffect, useState } from "react" import { PuffLoader } from "react-spinners" import { getAvatarURL } from "@/api/media.ts" import { useRoomMember } from "@/api/statestore" -import { MemberEventContent, UserID, UserProfile, Presence } from "@/api/types" +import { MemberEventContent, UserID, UserProfile } from "@/api/types" import { getLocalpart } from "@/util/validation.ts" import ClientContext from "../ClientContext.ts" import { LightboxContext } from "../modal" @@ -26,7 +26,6 @@ import UserExtendedProfile from "./UserExtendedProfile.tsx" import DeviceList from "./UserInfoDeviceList.tsx" import UserInfoError from "./UserInfoError.tsx" import MutualRooms from "./UserInfoMutualRooms.tsx" -import { ErrorResponse } from "@/api/rpc.ts" import { UserPresence } from "./UserPresence.tsx" interface UserInfoProps { diff --git a/web/src/ui/rightpanel/UserPresence.tsx b/web/src/ui/rightpanel/UserPresence.tsx index fc1a877..36053da 100644 --- a/web/src/ui/rightpanel/UserPresence.tsx +++ b/web/src/ui/rightpanel/UserPresence.tsx @@ -1,5 +1,5 @@ // gomuks - A Matrix client written in Go. -// Copyright (C) 2024 Tulir Asokan +// Copyright (C) 2025 Nexus Nicholson // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -13,10 +13,10 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -import { MouseEvent, useEffect, useState } from "react" -import { UserID, Presence, RPCEvent } from "@/api/types" -import { ErrorResponse } from "@/api/rpc.ts" +import { FormEvent, MouseEvent, useEffect, useState } from "react" import Client from "@/api/client" +import { ErrorResponse } from "@/api/rpc.ts" +import { Presence, RPCEvent, UserID } from "@/api/types" interface UserPresenceProps { client: Client, @@ -28,98 +28,139 @@ interface EditUserPresenceProps { setter: (presence: Presence) => void } const PresenceEmojis = { - "online": , - "offline": , - "unavailable": , + "online": , + "offline": , + "unavailable": , } export const UserPresence = ({ client, userID }: UserPresenceProps) => { - const [presence, setPresence] = useState(null) - const [errors, setErrors] = useState(null) + const [presence, setPresence] = useState(null) + const [errors, setErrors] = useState(null) - client.rpc.event.listen((event: RPCEvent) => { - if (event.command === "update_presence" && event.data.user_id === userID) { - setPresence({ - "presence": event.data.presence, - "status_msg": event.data.status_msg || null - }) - } - }) + client.rpc.event.listen((event: RPCEvent) => { + if (event.command === "update_presence" && event.data.user_id === userID) { + setPresence({ + "presence": event.data.presence, + "status_msg": event.data.status_msg || null, + }) + } + }) - useEffect(() => { - client.rpc.getPresence(userID).then( + useEffect(() => { + client.rpc.getPresence(userID).then( setPresence, err => { // A 404 is to be expected if the user has not federated presence. if (err instanceof ErrorResponse && err.message.startsWith("M_NOT_FOUND")) { setPresence(null) } else { - errors?.length ? setErrors([...errors, `${err}`]) : setErrors([`${err}`]) + setErrors([...errors||[], `${err}`]) } - } + }, ) - }, [client, userID]) + }, [client, userID]) - if(!presence) return null; + if(!presence) {return null} - return ( - <> - - { - userID === client.userID && - } - - ) + return ( + <> + + { + userID === client.userID && + } + + ) } export const DisplayUserPresence = ({ presence }: { presence: Presence | null }) => { - if(!presence) return null - return ( - <> -
{PresenceEmojis[presence.presence]} {presence.presence}
- { - presence.status_msg && ( -
{presence.status_msg}
- ) - } - - ) + if(!presence) {return null} + return ( + <> +
{PresenceEmojis[presence.presence]} {presence.presence} +
+ { + presence.status_msg && ( +
+
{presence.status_msg}
+
+ ) + } + + ) } export const EditUserPresence = ({ client, presence, setter }: EditUserPresenceProps) => { - const sendNewPresence = (newPresence: Presence) => { + const sendNewPresence = (newPresence: Presence) => { client.rpc.setPresence(newPresence).then( () => setter(newPresence), err => console.error(err), ) } - const clearStatusMessage = (e: MouseEvent) => { - let p = presence || {"presence": "offline"} - if(p.status_msg) { - delete p.status_msg - } - const textInputElement = e.currentTarget.parentElement?.querySelector("input[type=text]") as HTMLInputElement - client.rpc.setPresence(p).then( - () => {setter(p); if(textInputElement) textInputElement.value = ""}, + const createPresence = (status: "online" | "unavailable" | "offline") => { + return { ...(presence || {}), "presence": status } + } + const clearStatusMessage = (e: MouseEvent) => { + const p = presence || { "presence": "offline" } + if(p.status_msg) { + delete p.status_msg + } + const textInputElement = e.currentTarget.parentElement?.querySelector("input[type=text]") as HTMLInputElement + client.rpc.setPresence(p).then( + () => {setter(p); if(textInputElement) {textInputElement.value = ""}}, err => console.error(err), ) - } - return ( - <> -

Set presence

+ } + const onFormSubmit = (e: FormEvent) => { + e.preventDefault() + const textInputElement = e.currentTarget[0] as HTMLInputElement + const newPresence = { ...(presence || {}), "status_msg": textInputElement.value } + client.rpc.setPresence(newPresence).then( + () => {setter(newPresence); textInputElement.value = ""}, + err => console.error(err), + ) + } + + return ( + <> +

Set presence

- - - + + +

-
{e.preventDefault(); sendNewPresence({...(presence || {}), "status_msg": (e.currentTarget[0] as HTMLInputElement).value})}}> + - {presence?.status_msg && } + {presence?.status_msg && + }
- - ) + + ) }