diff --git a/packages/chat/src/components/message.tsx b/packages/chat/src/components/message.tsx index 997f42f..de819fc 100644 --- a/packages/chat/src/components/message.tsx +++ b/packages/chat/src/components/message.tsx @@ -143,7 +143,7 @@ function MessageComponent({ }, [message.Content]); // Message editing - const { chatSecret, editMessage, userId } = useChat(); + const { chatSecret, editMessage, userId, deleteMessage } = useChat(); const [editing, setEditing] = useState(false); const [editDraft, setEditDraft] = useState(message.Content); useEffect(() => { @@ -283,14 +283,46 @@ function MessageComponent({ )} {editing ? ( - { - submitEditMessage(editDraft); - setEditing(false); - }} - /> +
+ { + submitEditMessage(editDraft); + setEditing(false); + }} + /> +
+ + +
+
) : isValidURL ? ( ) : ( diff --git a/packages/chat/src/context.tsx b/packages/chat/src/context.tsx index af0226f..384f3c6 100644 --- a/packages/chat/src/context.tsx +++ b/packages/chat/src/context.tsx @@ -436,6 +436,65 @@ export default function Provider({ children }: { children: ReactNode }) { [currentChatSecret, userIdValue], ); + const deleteMessage = useCallback( + async (sendTime: number) => { + try { + const response = await send("MessageDelete", { + ChatPartnerId: userIdValue, + SendTime: sendTime, + }); + + assertProtocolSuccess("MessageDelete", response); + + setLiveMessagesState((prev) => + prev.filter((message) => message.SendTime !== sendTime), + ); + + const queryKey = [ + "chat-messages", + String(userIdValue), + currentChatSecret !== null, + ] as const; + + queryClient.setQueryData>( + queryKey, + (current) => { + if (!current) { + return current; + } + + let updated = false; + + const pages = current.pages.map((page) => { + const nextPage = page.filter((message) => { + const keep = message.SendTime !== sendTime; + if (!keep) { + updated = true; + } + return keep; + }); + + return nextPage; + }); + + if (!updated) { + return current; + } + + return { + ...current, + pages, + }; + }, + ); + } catch (err) { + log(1, "chat", "red", "Failed to delete message", err); + toast("error", "Failed to delete message", String(err)); + } + }, + [currentChatSecret, send, userIdValue], + ); + const addLiveMessage = useCallback( (message: RawMessage) => { const localId = @@ -578,6 +637,7 @@ export default function Provider({ children }: { children: ReactNode }) { liveMessages: () => liveMessagesState, addLiveMessage, editMessage, + deleteMessage, clearLiveMessages, chatSecret: currentChatSecret, userId: userIdValue, @@ -602,6 +662,7 @@ type contextType = { setFailed: (failed: boolean) => void; }; editMessage: (sendTime: number, edit: MessageEdit) => void; + deleteMessage: (sendTime: number) => void; clearLiveMessages: () => void; chatSecret: Uint8Array | null; userId: number; diff --git a/packages/shared/src/data.ts b/packages/shared/src/data.ts index 5bba99a..e065598 100644 --- a/packages/shared/src/data.ts +++ b/packages/shared/src/data.ts @@ -202,6 +202,13 @@ export const mtp = { PingIota: z.number(), }), }, + MessageDelete: { + request: z.object({ + ChatPartnerId: z.number(), + SendTime: z.number(), + }), + response: z.object({}), + }, MessageEditLive: { request: z.object({}), response: z.object({