fix(threads): polls created from a thread composer land in the thread
PollCreator used the legacy 3-arg sendEvent (threadId null). Thread the composer's threadRootId through and send like the sticker path. Also (#41, same file): composer drafts are persisted as { userId, nodes } and the restore path drops any draft with a different or missing userId. Fixes #35 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
@@ -398,27 +398,47 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
||||
try {
|
||||
const stored = localStorage.getItem(`draft-msg-${draftKey}`);
|
||||
if (stored) {
|
||||
const nodes = JSON.parse(stored);
|
||||
if (Array.isArray(nodes) && nodes.length > 0) {
|
||||
Transforms.insertFragment(editor, nodes);
|
||||
// Mirror the restored draft into the atom so the draft indicator
|
||||
// (reads roomIdToMsgDraftAtomFamily) reflects a persisted draft
|
||||
// after a page reload — not only on same-session room re-entry.
|
||||
setMsgDraft(nodes);
|
||||
const parsed = JSON.parse(stored);
|
||||
// [Gitea #41] Only restore a draft this same account wrote. A legacy
|
||||
// draft (stored as a bare array, pre-dating user-scoping) or one
|
||||
// written by a different userId is foreign — drop it rather than
|
||||
// risk pre-filling another account's unsent text into the composer.
|
||||
const foreign =
|
||||
!parsed ||
|
||||
typeof parsed !== 'object' ||
|
||||
Array.isArray(parsed) ||
|
||||
parsed.userId !== mx.getUserId();
|
||||
if (foreign) {
|
||||
localStorage.removeItem(`draft-msg-${draftKey}`);
|
||||
} else {
|
||||
const nodes = parsed.nodes;
|
||||
if (Array.isArray(nodes) && nodes.length > 0) {
|
||||
Transforms.insertFragment(editor, nodes);
|
||||
// Mirror the restored draft into the atom so the draft indicator
|
||||
// (reads roomIdToMsgDraftAtomFamily) reflects a persisted draft
|
||||
// after a page reload — not only on same-session room re-entry.
|
||||
setMsgDraft(nodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Ignore malformed stored draft
|
||||
}
|
||||
}
|
||||
}, [editor, msgDraft, draftKey, setMsgDraft]);
|
||||
}, [editor, msgDraft, draftKey, setMsgDraft, mx]);
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
if (!isEmptyEditor(editor)) {
|
||||
const parsedDraft = JSON.parse(JSON.stringify(editor.children));
|
||||
setMsgDraft(parsedDraft);
|
||||
localStorage.setItem(`draft-msg-${draftKey}`, JSON.stringify(parsedDraft));
|
||||
// [Gitea #41] Tag the persisted draft with the writing user's id so a
|
||||
// different account logging into this browser can't have it hydrated
|
||||
// into their composer (see useHydrateMsgDrafts / clearPlaintextCaches).
|
||||
localStorage.setItem(
|
||||
`draft-msg-${draftKey}`,
|
||||
JSON.stringify({ userId: mx.getUserId(), nodes: parsedDraft }),
|
||||
);
|
||||
} else {
|
||||
setMsgDraft([]);
|
||||
localStorage.removeItem(`draft-msg-${draftKey}`);
|
||||
@@ -426,7 +446,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
||||
resetEditor(editor);
|
||||
resetEditorHistory(editor);
|
||||
},
|
||||
[draftKey, editor, setMsgDraft],
|
||||
[draftKey, editor, setMsgDraft, mx],
|
||||
);
|
||||
|
||||
const handleFileMetadata = useCallback(
|
||||
@@ -1480,7 +1500,14 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
||||
</>
|
||||
}
|
||||
/>
|
||||
{pollOpen && <PollCreator room={room} roomId={roomId} onClose={() => setPollOpen(false)} />}
|
||||
{pollOpen && (
|
||||
<PollCreator
|
||||
room={room}
|
||||
roomId={roomId}
|
||||
threadRootId={threadRootId}
|
||||
onClose={() => setPollOpen(false)}
|
||||
/>
|
||||
)}
|
||||
{scheduleOpen && (
|
||||
<ScheduleMessageModal
|
||||
roomId={roomId}
|
||||
|
||||
Reference in New Issue
Block a user