feat/lc-62-scheduled-send-pr-b #157
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/lc-62-scheduled-send-pr-b"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The modal lives in layout.html's persistent shell so the open/close JS does not have to be re-bound on composer swaps. The trigger (the clock-icon button next to Send in composer.html) calls window.__lcOpenScheduledModal(), which reads the current composer's data-room-id + body + file_id at open time so a composer swap between page-load and trigger does not leak stale references. The composer form gains a data-room-id attribute (already had hx-post="/room/{id}/messages" so the value is colocated, just exposed for JS now). Reuses Phase 25's window.__lcDialogTrap(rootElement) from layout.html for Tab cycling; ESC + backdrop click + Cancel + X + submit-success are each handled explicitly because __lcDialogTrap only wraps Tab (call.js's pattern, mirrored here). aria attributes: role="dialog" + aria-modal="true" + aria-labelledby on the dialog, aria-haspopup="dialog" on the trigger. Native <input type="datetime-local"> per the ticket decision. On submit, JS converts the picker's local value to a Date, then to UTC via toISOString(), and POSTs the result as scheduled_for; the route in Task 4 accepts RFC3339 and stores in SQLite's YYYY-MM-DD HH:MM:SS format. Submit goes via fetch rather than HTMX so close-on-success + show-error-on-fail can branch on res.ok without binding a target. Composer reset on success mirrors the live-send afterRequest path (clear textarea, disable send, clear attachment) so a scheduled send feels like a normal send from the composer's perspective. Best-effort: if the composer was swapped away mid-modal, the reset block is a no-op via document.contains check. Close-path enumeration (all funnel through closeModal which disposes the trap exactly once, restores aria-hidden, and refocuses the opener if it still exists): 1. Cancel button (data-lc-scheduled-modal-cancel) 2. X button (data-lc-scheduled-modal-close) 3. ESC keydown (keydown listener on the dialog root; __lcDialogTrap only wraps Tab) 4. Backdrop click (mousedown on the dialog root where target === root; mousedown rather than click so a drag that starts inside the panel and releases on the backdrop does not dismiss) 5. Submit success (fetch returns 2xx) UI behavior is NOT browser-verified in this commit. The close paths, focus restoration, aria-hidden flipping, datetime conversion, and end-to-end "click Schedule, wait 30s, observe delivery" flow were not exercised against a running dev-web-local. The code matches the close-path enumeration above through review only; manual smoke verification is deferred to Task 8 (README + verification pass). Excluded by design: no Submit-failure close path (errors show inline in the modal so the user can adjust and retry without losing the open dialog). No browser back-button close (modal does not push history state in v1). No new test binary. Task 4's POST /scheduled wire-shape tests cover the route the modal targets; UI behavior is hard to integration-test and the alternative (headless browser harness) is overkill for one dialog.