(feat): add message deletions
All checks were successful
/ build-web (push) Successful in 7m26s
/ build-desktop (linux) (push) Successful in 12m17s
/ build-mobile (push) Successful in 19m18s
/ release (push) Successful in 3m0s

This commit is contained in:
Alois 2026-07-11 11:25:45 +02:00
commit c11589079b
3 changed files with 109 additions and 9 deletions

View file

@ -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({
</div>
)}
{editing ? (
<Input
setValue={setEditDraft}
value={editDraft}
onSubmit={() => {
submitEditMessage(editDraft);
setEditing(false);
}}
/>
<div className="flex flex-col">
<Input
styled
setValue={setEditDraft}
value={editDraft}
onSubmit={() => {
submitEditMessage(editDraft);
setEditing(false);
}}
/>
<div className="flex">
<Button
size="xs"
variant="link"
className="text-primary-foreground-alt"
onClick={() => {
if (editDraft === message.Content) {
deleteMessage(message.SendTime);
} else {
submitEditMessage(editDraft);
}
setEditDraft(message.Content);
setEditing(false);
}}
>
Save
</Button>
<Button
size="xs"
variant="link"
className="text-muted-foreground"
onClick={() => {
setEditDraft(message.Content);
setEditing(false);
}}
>
Cancel
</Button>
</div>
</div>
) : isValidURL ? (
<Media link={message.Content} />
) : (

View file

@ -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<InfiniteData<RawMessages>>(
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;

View file

@ -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({