Display reactions below messages

This commit is contained in:
2025-11-28 14:37:17 +01:00
parent 9f0bc3303c
commit 6c11979ef2
3 changed files with 108 additions and 9 deletions

View File

@@ -5,6 +5,7 @@ import {
Box,
Button,
ButtonGroup,
Chip,
Dialog,
DialogActions,
DialogContent,
@@ -22,8 +23,14 @@ import type { Room } from "../../api/matrix/MatrixApiRoom";
import { useAlert } from "../../hooks/contexts_provider/AlertDialogProvider";
import { useConfirm } from "../../hooks/contexts_provider/ConfirmDialogProvider";
import { useLoadingMessage } from "../../hooks/contexts_provider/LoadingMessageProvider";
import type { Message, RoomEventsManager } from "../../utils/RoomEventsManager";
import { useSnackbar } from "../../hooks/contexts_provider/SnackbarProvider";
import type {
Message,
MessageReaction,
RoomEventsManager,
} from "../../utils/RoomEventsManager";
import { useUserInfo } from "../dashboard/BaseAuthenticatedPage";
import { EmojiIcon } from "../EmojiIcon";
import { AccountIcon } from "./AccountIcon";
export function RoomMessagesList(p: {
@@ -83,6 +90,7 @@ function RoomMessage(p: {
const user = useUserInfo();
const alert = useAlert();
const confirm = useConfirm();
const snackbar = useSnackbar();
const loadingMessage = useLoadingMessage();
const [showImageFullScreen, setShowImageFullScreen] = React.useState(false);
@@ -140,6 +148,20 @@ function RoomMessage(p: {
}
};
const handleToggleReaction = async (
key: string,
reaction: MessageReaction
) => {
try {
if (!reaction)
await MatrixApiEvent.ReactToEvent(p.room, p.message.event_id, key);
else await MatrixApiEvent.DeleteEvent(p.room, reaction.event_id);
} catch (e) {
console.error(`Failed to toggle reaction!`, e);
snackbar(`Failed to toggle reaction! ${e}`);
}
};
return (
<>
{/* Print date if required */}
@@ -243,6 +265,49 @@ function RoomMessage(p: {
</ButtonGroup>
</Box>
{/* Reaction */}
<Box sx={{ marginLeft: "50px" }}>
{[...p.message.reactions.keys()].map((r) => {
const userReaction = p.message.reactions
.get(r)!
.find((r) => r.account === user.info.matrix_user_id);
return (
<Chip
size="small"
style={{
height: "2em",
marginRight: "5px",
maxHeight: "unset",
cursor: "pointer",
}}
slotProps={{
root: { onClick: () => handleToggleReaction(r, userReaction) },
label: { style: { height: "2em" } },
}}
color={userReaction !== undefined ? "success" : undefined}
variant="filled"
label={
<span
style={{
display: "inline-flex",
justifyContent: "center",
alignItems: "center",
flexDirection: "row",
}}
>
<div style={{ margin: "3px 3px" }}>
<EmojiIcon emojiKey={r} />
</div>
<div style={{ height: "2em", marginLeft: "2px" }}>
{p.message.reactions.get(r)?.length}
</div>
</span>
}
/>
);
})}
</Box>
{/* Full screen image dialog */}
<Dialog open={showImageFullScreen} onClose={closeImageFullScreen}>
<img
@@ -315,11 +380,17 @@ function ReactionButton(p: {
// Do not offer to react to existing reactions
if (
p.message.reactions.find(
(r) => r.key === p.emojiKey && r.account === user.info.matrix_user_id
) !== undefined
p.message.reactions
.get(p.emojiKey)
?.find(
(r) => r.key === p.emojiKey && r.account === user.info.matrix_user_id
) !== undefined
)
return <></>;
return <Button onClick={sendEmoji}>{p.emojiKey}</Button>;
return (
<Button onClick={sendEmoji}>
<EmojiIcon {...p} />
</Button>
);
}