cetirizine

An experimental matrix client written in reactjs utilizing tailwind and storybook
git clone git://archive.git.mtrnord.blog/MTRNord/cetirizine.git
Log | Files | Refs | README | LICENSE

commit f7a5fd119a689c7f07555e50acb9e96c23932c3b
parent 0eb0105231ec84775adebe0f873e37b069100229
Author: MTRNord <mtrnord1@gmail.com>
Date:   Sat,  6 May 2023 20:59:12 +0200

Render redactions

Diffstat:
Msrc/components/events/unknownEvent.tsx | 43++++++++++++++++++++++++++++++++++++++++---
Msrc/pages/MainPage.tsx | 33+++++++++++++++++++++++++++------
2 files changed, 67 insertions(+), 9 deletions(-)

diff --git a/src/components/events/unknownEvent.tsx b/src/components/events/unknownEvent.tsx @@ -63,7 +63,7 @@ type UndecryptableEventProps = { hasPreviousEvent?: boolean; }; -const UndecryptableEvent: FC<UndecryptableEventProps> = memo(({ event, roomID, hasPreviousEvent }) => { +export const UndecryptableEvent: FC<UndecryptableEventProps> = memo(({ event, roomID, hasPreviousEvent }) => { const room = useRoom(roomID); return ( @@ -82,4 +82,42 @@ const UndecryptableEvent: FC<UndecryptableEventProps> = memo(({ event, roomID, h ) }); -export { UndecryptableEvent }; -\ No newline at end of file +type RedactedEventProps = { + /** + * The original event + */ + event: IRoomEvent; + /** + * The event to render + */ + redacted_because?: string; + /** + * The roomID of the event to display + */ + roomID?: string; + /** + * If the previous event was sent by the same user + */ + hasPreviousEvent?: boolean; +}; + +export const RedactedEvent: FC<RedactedEventProps> = memo(({ event, redacted_because, roomID, hasPreviousEvent }) => { + const room = useRoom(roomID); + + return ( + <div className={!hasPreviousEvent ? "flex flex-row gap-4 p-2 pb-1 hover:bg-gray-200 rounded-md duration-200 ease-in-out items-start" : "flex flex-row p-2 pb-1 pt-0 hover:bg-gray-200 rounded-md duration-200 ease-in-out"}> + {!hasPreviousEvent && <Avatar + displayname={room?.getMemberName(event.sender) || ""} + avatarUrl={room?.getMemberAvatar(event.sender)} + online={room?.isOnline() || false} + dm={room?.isDM() || false} + />} + <div className={!hasPreviousEvent ? "flex flex-col gap-1" : "ml-[3.7rem]"}> + {!hasPreviousEvent && <h2 className="text-sm font-medium text-red-500 whitespace-normal">{room?.getMemberName(event.sender)}</h2>} + {redacted_because && <p className="whitespace-normal text-base font-normal text-blue-600 italic">{redacted_because}</p>} + <p className="whitespace-normal text-base font-normal text-blue-600 italic">Message was redacted</p> + </div> + </div> + ) +}); + diff --git a/src/pages/MainPage.tsx b/src/pages/MainPage.tsx @@ -9,7 +9,7 @@ import { FC, memo, useContext, useEffect, useRef, useState } from 'react'; import { MatrixContext } from '../app/sdk/client'; import { useLocation, useParams } from 'react-router-dom'; import MessageEvent from '../components/events/messageEvent'; -import UnknownEvent, { UndecryptableEvent } from '../components/events/unknownEvent'; +import UnknownEvent, { RedactedEvent, UndecryptableEvent } from '../components/events/unknownEvent'; import MemberEvent from '../components/events/memberEvent'; import { IRoomEvent, IRoomMemberEvent } from '../app/sdk/api/apiTypes'; import Linkify from 'linkify-react'; @@ -47,7 +47,7 @@ const ChatView: FC<ChatViewProps> = memo(({ roomID, scrollRef }) => { }); - Promise.all(dedupedEvents?.filter(event => event.type !== "m.reaction" && !event.content["m.relates_to"]).map(async (event, index) => { + Promise.all(dedupedEvents?.filter(event => event.type !== "m.reaction" && event.type !== "m.room.redaction" && !event.content["m.relates_to"]).map(async (event, index) => { let previousEvent = dedupedEvents?.filter(event => event.type !== "m.reaction")[index - 1]; const previousEventIsFromSameSender = previousEvent?.sender === event.sender; let previousEventType = previousEvent?.type; @@ -57,6 +57,20 @@ const ChatView: FC<ChatViewProps> = memo(({ roomID, scrollRef }) => { return e.type === "m.reaction" && e.content["m.relates_to"].event_id === event.event_id; }); + // Check if event is redacted + const redaction = dedupedEvents?.find((e) => { + return e.type === "m.room.redaction" && e.redacts === event.event_id; + }); + const redacted = redaction !== undefined; + let redacted_because = undefined; + let redaction_id = undefined; + if (redacted) { + redaction_id = redaction?.event_id; + if (redaction.content.reason) { + redacted_because = redaction.content.reason; + } + } + // Check if there is an edit (m.relates_to with rel_type of "m.replace") const edit = dedupedEvents?.find((e) => { if (!e.content["m.relates_to"]) { @@ -88,10 +102,16 @@ const ChatView: FC<ChatViewProps> = memo(({ roomID, scrollRef }) => { event.content.format = event.content["m.new_content"].format; } } else { + if (redacted) { + return (<RedactedEvent event={event} redacted_because={redacted_because} key={redaction_id} roomID={roomID} hasPreviousEvent={previousEventIsFromSameSender} />) + } return (<UndecryptableEvent key={event.event_id} event={event} hasPreviousEvent={previousEventIsFromSameSender} roomID={roomID}></UndecryptableEvent>) } } catch (e: any) { console.error(e); + if (redacted) { + return (<RedactedEvent event={event} redacted_because={redacted_because} key={redaction_id} roomID={roomID} hasPreviousEvent={previousEventIsFromSameSender} />) + } return (<UndecryptableEvent key={event.event_id} event={event} hasPreviousEvent={previousEventIsFromSameSender} roomID={roomID}></UndecryptableEvent>) } } @@ -114,7 +134,7 @@ const ChatView: FC<ChatViewProps> = memo(({ roomID, scrollRef }) => { } } - return renderEvent(event, previousEventIsFromSameSender, previousEventType, reactions); + return renderEvent(event, previousEventIsFromSameSender, previousEventType, reactions, redacted, redacted_because, redaction_id); })).then((renderedEvents) => { setRenderedEvents(renderedEvents); }); @@ -131,14 +151,15 @@ const ChatView: FC<ChatViewProps> = memo(({ roomID, scrollRef }) => { }, [pathname]); // Render events based on the event type and content - const renderEvent = (event: IRoomEvent, previousEventIsFromSameSender: boolean, previousEventType: string, reactions: IRoomEvent[]) => { + const renderEvent = (event: IRoomEvent, previousEventIsFromSameSender: boolean, previousEventType: string, reactions: IRoomEvent[], redacted: boolean, redacted_because: string, redaction_id?: string) => { + if (redacted) { + return (<RedactedEvent event={event} redacted_because={redacted_because} roomID={roomID} hasPreviousEvent={previousEventIsFromSameSender} key={redaction_id} />) + } switch (event.type) { case "m.room.message": return <MessageEvent reactions={reactions} event={event} roomID={roomID} key={event.event_id} hasPreviousEvent={previousEventIsFromSameSender && previousEventType === "m.room.message"} /> case "m.room.member": return <MemberEvent event={event as IRoomMemberEvent} key={event.event_id} /> - case "m.room.redaction": - return <></>; default: return <UnknownEvent event={event} key={event.event_id} /> }