web/timeline: fix rendering replies to non-message events

This commit is contained in:
Tulir Asokan 2024-10-21 20:35:20 +03:00
parent d73cf4d863
commit e1c937849e
3 changed files with 58 additions and 46 deletions

View file

@ -18,7 +18,7 @@ import { getAvatarURL } from "@/api/media.ts"
import { RoomStateStore, useRoomEvent } from "@/api/statestore" import { RoomStateStore, useRoomEvent } from "@/api/statestore"
import type { EventID, MemDBEvent, MemberEventContent } from "@/api/types" import type { EventID, MemDBEvent, MemberEventContent } from "@/api/types"
import { ClientContext } from "../ClientContext.ts" import { ClientContext } from "../ClientContext.ts"
import { TextMessageBody } from "./content/MessageBody.tsx" import getBodyType from "./content/getBodyType.ts"
import CloseButton from "@/icons/close.svg?react" import CloseButton from "@/icons/close.svg?react"
import "./ReplyBody.css" import "./ReplyBody.css"
@ -65,6 +65,7 @@ const onClickReply = (evt: React.MouseEvent) => {
export const ReplyBody = ({ room, event, onClose }: ReplyBodyProps) => { export const ReplyBody = ({ room, event, onClose }: ReplyBodyProps) => {
const memberEvt = room.getStateEvent("m.room.member", event.sender) const memberEvt = room.getStateEvent("m.room.member", event.sender)
const memberEvtContent = memberEvt?.content as MemberEventContent | undefined const memberEvtContent = memberEvt?.content as MemberEventContent | undefined
const BodyType = getBodyType(event, true)
return <blockquote return <blockquote
data-reply-to={event.event_id} data-reply-to={event.event_id}
className={`reply-body ${onClose ? "composer" : ""}`} className={`reply-body ${onClose ? "composer" : ""}`}
@ -82,6 +83,6 @@ export const ReplyBody = ({ room, event, onClose }: ReplyBodyProps) => {
<span className="event-sender">{memberEvtContent?.displayname || event.sender}</span> <span className="event-sender">{memberEvtContent?.displayname || event.sender}</span>
{onClose && <button className="close-reply" onClick={onClose}><CloseButton/></button>} {onClose && <button className="close-reply" onClick={onClose}><CloseButton/></button>}
</div> </div>
<TextMessageBody room={room} event={event}/> <BodyType room={room} event={event}/>
</blockquote> </blockquote>
} }

View file

@ -21,11 +21,9 @@ import { isEventID } from "@/util/validation.ts"
import { ClientContext } from "../ClientContext.ts" import { ClientContext } from "../ClientContext.ts"
import { LightboxContext } from "../Lightbox.tsx" import { LightboxContext } from "../Lightbox.tsx"
import { ReplyIDBody } from "./ReplyBody.tsx" import { ReplyIDBody } from "./ReplyBody.tsx"
import EncryptedBody from "./content/EncryptedBody.tsx"
import HiddenEvent from "./content/HiddenEvent.tsx" import HiddenEvent from "./content/HiddenEvent.tsx"
import MemberBody from "./content/MemberBody.tsx" import MemberBody from "./content/MemberBody.tsx"
import { MediaMessageBody, TextMessageBody, UnknownMessageBody } from "./content/MessageBody.tsx" import getBodyType from "./content/getBodyType.ts"
import RedactedBody from "./content/RedactedBody.tsx"
import { EventContentProps } from "./content/props.ts" import { EventContentProps } from "./content/props.ts"
import ErrorIcon from "../../icons/error.svg?react" import ErrorIcon from "../../icons/error.svg?react"
import PendingIcon from "../../icons/pending.svg?react" import PendingIcon from "../../icons/pending.svg?react"
@ -39,47 +37,6 @@ export interface TimelineEventProps {
setReplyToRef: React.RefObject<(evt: EventID | null) => void> setReplyToRef: React.RefObject<(evt: EventID | null) => void>
} }
function getBodyType(evt: MemDBEvent): React.FunctionComponent<EventContentProps> {
if (evt.relation_type === "m.replace") {
return HiddenEvent
}
switch (evt.type) {
case "m.room.message":
if (evt.redacted_by) {
return RedactedBody
}
switch (evt.content.msgtype) {
case "m.text":
case "m.notice":
case "m.emote":
return TextMessageBody
case "m.image":
case "m.video":
case "m.audio":
case "m.file":
return MediaMessageBody
case "m.location":
// return LocationMessageBody
// fallthrough
default:
return UnknownMessageBody
}
case "m.sticker":
if (evt.redacted_by) {
return RedactedBody
}
return MediaMessageBody
case "m.room.encrypted":
if (evt.redacted_by) {
return RedactedBody
}
return EncryptedBody
case "m.room.member":
return MemberBody
}
return HiddenEvent
}
const fullTimeFormatter = new Intl.DateTimeFormat("en-GB", { dateStyle: "full", timeStyle: "medium" }) const fullTimeFormatter = new Intl.DateTimeFormat("en-GB", { dateStyle: "full", timeStyle: "medium" })
const dateFormatter = new Intl.DateTimeFormat("en-GB", { dateStyle: "full" }) const dateFormatter = new Intl.DateTimeFormat("en-GB", { dateStyle: "full" })
const formatShortTime = (time: Date) => const formatShortTime = (time: Date) =>

View file

@ -0,0 +1,54 @@
import React from "react"
import { MemDBEvent } from "@/api/types"
import EncryptedBody from "./EncryptedBody.tsx"
import HiddenEvent from "./HiddenEvent.tsx"
import MemberBody from "./MemberBody.tsx"
import { MediaMessageBody, TextMessageBody, UnknownMessageBody } from "./MessageBody.tsx"
import RedactedBody from "./RedactedBody.tsx"
import { EventContentProps } from "./props.ts"
export default function getBodyType(evt: MemDBEvent, forReply = false): React.FunctionComponent<EventContentProps> {
if (evt.relation_type === "m.replace") {
return HiddenEvent
}
switch (evt.type) {
case "m.room.message":
if (evt.redacted_by) {
return RedactedBody
}
switch (evt.content.msgtype) {
case "m.text":
case "m.notice":
case "m.emote":
return TextMessageBody
case "m.image":
case "m.video":
case "m.audio":
case "m.file":
if (forReply) {
return TextMessageBody
}
return MediaMessageBody
case "m.location":
// return LocationMessageBody
// fallthrough
default:
return UnknownMessageBody
}
case "m.sticker":
if (evt.redacted_by) {
return RedactedBody
} else if (forReply) {
return TextMessageBody
}
return MediaMessageBody
case "m.room.encrypted":
if (evt.redacted_by) {
return RedactedBody
}
return EncryptedBody
case "m.room.member":
return MemberBody
}
return HiddenEvent
}