feat(scheduling): edit / reschedule a scheduled message
CI / Build & Quality Checks (push) Successful in 11m43s
CI / Trigger Desktop Build (push) Successful in 8s

The scheduled-messages tray was cancel-only. Add an inline edit button
that re-opens ScheduleMessageModal seeded with the existing body and
send-time, letting the user change the text and/or when it sends.

MSC4140 has no in-place edit, so an edit is schedule-new + cancel-old.
Order matters: the modal schedules the new delayed event first, then we
cancel the old one and only prune it from local state once the server
confirms. A failed cancel therefore leaves a visible, retriable copy in
the tray instead of silently letting the stale message fire or losing
the edit. Edits go through the plain-text composer, so rich content
collapses to m.text (acceptable for v1).

ScheduleMessageModal gains optional initialSendAt (seed the pickers) and
title props so it is reusable for both scheduling and editing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-09 22:47:43 -04:00
co-authored by Claude Opus 4.8
parent 7d02f4e538
commit 5d5ae0ee70
3 changed files with 78 additions and 12 deletions
@@ -26,6 +26,10 @@ interface ScheduleMessageModalProps {
roomId: string;
/** Pre-fill the message body from the composer. Pass null/undefined to open blank. */
initialBody?: string;
/** Pre-fill the date/time pickers (Unix ms) — used when editing/rescheduling. */
initialSendAt?: number;
/** Header title; defaults to "Schedule Message". */
title?: string;
onScheduled: (delayId: string, sendAt: number, content: IContent) => void;
onClose: () => void;
}
@@ -88,6 +92,8 @@ const pickerInputStyle = (c: typeof color, cfg: typeof config): React.CSSPropert
export function ScheduleMessageModal({
roomId,
initialBody,
initialSendAt,
title = 'Schedule Message',
onScheduled,
onClose,
}: ScheduleMessageModalProps) {
@@ -105,7 +111,8 @@ export function ScheduleMessageModal({
return d;
};
const def = defaultDate();
// When editing, seed the pickers from the existing send-time; else default to +1h.
const def = initialSendAt ? new Date(initialSendAt) : defaultDate();
const [dateValue, setDateValue] = useState<string>(() => toLocalDate(def));
const [timeValue, setTimeValue] = useState<string>(() => toLocalTime(def));
@@ -199,7 +206,7 @@ export function ScheduleMessageModal({
<Box grow="Yes" alignItems="Center" gap="200">
<Icon src={Icons.Clock} size="100" />
<Text id="schedule-message-title" size="H4">
Schedule Message
{title}
</Text>
</Box>
<IconButton size="300" radii="300" onClick={onClose} aria-label="Close">