(feat): add message editing
(qol): update todos
This commit is contained in:
parent
f61a77af31
commit
8dd73568ce
8 changed files with 310 additions and 6 deletions
|
|
@ -27,6 +27,10 @@ import MessageContextMenu from "./messageContextMenu";
|
|||
import Media from "./media";
|
||||
import { useStorage } from "@tensamin/storage/context";
|
||||
import { useMTP } from "@tensamin/mtp";
|
||||
import Input from "@tensamin/markdown/input";
|
||||
import { useChat } from "../context";
|
||||
import { encryptChatText } from "@tensamin/crypto/chatSecret";
|
||||
import { log, toast } from "@tensamin/shared/log";
|
||||
|
||||
function MessageComponent({
|
||||
grouped,
|
||||
|
|
@ -138,6 +142,62 @@ function MessageComponent({
|
|||
}
|
||||
}, [message.Content]);
|
||||
|
||||
// Message editing
|
||||
const { chatSecret, editMessageContent, userId } = useChat();
|
||||
const [editing, setEditing] = useState(false);
|
||||
const [editDraft, setEditDraft] = useState(message.Content);
|
||||
useEffect(() => {
|
||||
if (!editing) {
|
||||
setEditDraft(message.Content);
|
||||
}
|
||||
}, [editing, message.Content]);
|
||||
const editMessage = useCallback(
|
||||
async (newContent: string) => {
|
||||
if (!chatSecret) return;
|
||||
|
||||
const encryptedContent = await encryptChatText(
|
||||
chatSecret,
|
||||
newContent,
|
||||
).catch((err) => {
|
||||
toast("error", "Failed to encrypt edit", String(err));
|
||||
});
|
||||
|
||||
if (!encryptedContent) return;
|
||||
|
||||
const previousContent = message.Content;
|
||||
editMessageContent(message.SendTime, newContent);
|
||||
|
||||
try {
|
||||
const response = await send("MessageEdit", {
|
||||
ChatPartnerId: userId,
|
||||
Content: encryptedContent,
|
||||
SendTime: message.SendTime,
|
||||
});
|
||||
|
||||
if (response.type.startsWith("Error")) {
|
||||
throw new Error(response.type);
|
||||
}
|
||||
} catch (err) {
|
||||
editMessageContent(
|
||||
message.SendTime,
|
||||
previousContent,
|
||||
message.Edited ?? false,
|
||||
);
|
||||
log(1, "chat", "red", "Failed to edit message", err);
|
||||
toast("error", "Failed to edit message", String(err));
|
||||
}
|
||||
},
|
||||
[
|
||||
chatSecret,
|
||||
editMessageContent,
|
||||
userId,
|
||||
message.Content,
|
||||
message.Edited,
|
||||
message.SendTime,
|
||||
send,
|
||||
],
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
// pt-3 is to get a gap between messages
|
||||
|
|
@ -147,6 +207,8 @@ function MessageComponent({
|
|||
<MessageContextMenu
|
||||
content={message.Content}
|
||||
messageId={message.SendTime}
|
||||
onSetEditing={setEditing}
|
||||
senderId={message.SenderId}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
|
|
@ -221,7 +283,16 @@ function MessageComponent({
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
{isValidURL ? (
|
||||
{editing ? (
|
||||
<Input
|
||||
setValue={setEditDraft}
|
||||
value={editDraft}
|
||||
onSubmit={() => {
|
||||
editMessage(editDraft);
|
||||
setEditing(false);
|
||||
}}
|
||||
/>
|
||||
) : isValidURL ? (
|
||||
<Media link={message.Content} />
|
||||
) : (
|
||||
<Text value={message.Content} />
|
||||
|
|
|
|||
|
|
@ -17,9 +17,10 @@ import {
|
|||
useIsMobile,
|
||||
} from "@tensamin/ui";
|
||||
import { Pin, Clipboard, Pen, Reply, Forward, Trash } from "lucide-react";
|
||||
import { useMemo, useState } from "react";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import type { ReactElement, ReactNode } from "react";
|
||||
import { useChat } from "../context";
|
||||
import { useStorage } from "@tensamin/storage/context";
|
||||
|
||||
async function copyText(text: string) {
|
||||
await navigator.clipboard.writeText(text);
|
||||
|
|
@ -136,6 +137,8 @@ function MessageMenuContent({
|
|||
messageId,
|
||||
onAddReaction,
|
||||
showReactionItems = true,
|
||||
onSetEditing,
|
||||
senderId,
|
||||
}: {
|
||||
components: MenuComponents;
|
||||
content: string;
|
||||
|
|
@ -143,12 +146,20 @@ function MessageMenuContent({
|
|||
messageId: number;
|
||||
onAddReaction?: () => void | Promise<void>;
|
||||
showReactionItems?: boolean;
|
||||
onSetEditing: (value: boolean) => void;
|
||||
senderId: number;
|
||||
}) {
|
||||
const { Content, Group, Item, Separator, Sub, SubContent, SubTrigger } =
|
||||
components;
|
||||
|
||||
const { load } = useStorage();
|
||||
const { setReplyTo } = useChat();
|
||||
|
||||
const [ownId, setOwnId] = useState(0);
|
||||
useEffect(() => {
|
||||
load("user_id").then(setOwnId);
|
||||
}, [load]);
|
||||
|
||||
return (
|
||||
<Content>
|
||||
<Group>
|
||||
|
|
@ -172,9 +183,16 @@ function MessageMenuContent({
|
|||
</Group>
|
||||
<Separator />
|
||||
<Group>
|
||||
<Item disabled className="flex justify-between">
|
||||
<p>Edit Message</p> <Pen />
|
||||
</Item>
|
||||
{senderId === ownId && (
|
||||
<Item
|
||||
className="flex justify-between"
|
||||
onClick={() => {
|
||||
onSetEditing(true);
|
||||
}}
|
||||
>
|
||||
<p>Edit Message</p> <Pen />
|
||||
</Item>
|
||||
)}
|
||||
<Item
|
||||
className="flex justify-between"
|
||||
onClick={() => {
|
||||
|
|
@ -214,10 +232,14 @@ export default function MessageContextMenu({
|
|||
children,
|
||||
content,
|
||||
messageId,
|
||||
onSetEditing,
|
||||
senderId,
|
||||
}: {
|
||||
children: ReactElement;
|
||||
content: string;
|
||||
messageId: number;
|
||||
onSetEditing: (value: boolean) => void;
|
||||
senderId: number;
|
||||
}) {
|
||||
const isMobile = useIsMobile();
|
||||
const devEnabled = useMemo(
|
||||
|
|
@ -257,6 +279,8 @@ export default function MessageContextMenu({
|
|||
messageId={messageId}
|
||||
onAddReaction={() => setReactionDrawerOpen(true)}
|
||||
showReactionItems={false}
|
||||
onSetEditing={onSetEditing}
|
||||
senderId={senderId}
|
||||
/>
|
||||
</Drawer>
|
||||
<Drawer open={reactionDrawerOpen} onOpenChange={setReactionDrawerOpen}>
|
||||
|
|
@ -282,6 +306,8 @@ export default function MessageContextMenu({
|
|||
content={content}
|
||||
devEnabled={devEnabled}
|
||||
messageId={messageId}
|
||||
onSetEditing={onSetEditing}
|
||||
senderId={senderId}
|
||||
/>
|
||||
</ContextMenu>
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue