Skip to content

Commit 61baa19

Browse files
committed
fix(editor): live preview shows the whole recurring series, not just one event
Recurrence rows ("+ Add recurrence") were only ever expanded into real occurrences at Review & submit time (proposeOrGenerate), so the live preview added earlier never reflected them — it kept showing exactly one card (the shared template) no matter how many dates the series would actually generate. refresh() now reuses the same expansion (buildRecurringEvents + expandRecurrenceDates) used by Review & submit, via getRecurrenceSeries(), and previews every occurrence once at least one recurrence row exists. Falls back to the single-event preview when there are no rows, including in bulk-edit mode, where renderForm never wires recurrence rows at all. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent c8d48e7 commit 61baa19

3 files changed

Lines changed: 42 additions & 9 deletions

File tree

apps/editor/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ tied to semver releases.
66

77
## 2026-08-13
88

9+
- **Live preview now shows the whole series, not just the template**: once
10+
one or more "+ Add recurrence" rows exist, the preview expands them the
11+
same way Review & submit would (`buildRecurringEvents`/
12+
`expandRecurrenceDates`) and shows every generated occurrence, instead of
13+
a single card for the shared template. Previously the preview always
14+
showed exactly one event regardless of any recurrence rows, since they
15+
were only ever expanded at Review & submit time.
916
- **Live preview**: the form now renders the event being edited with the
1017
same `<ote-events>` widget (`apps/embed`) used elsewhere in the app, fed
1118
purely in-memory from the current draft (`layout="cards"`, debounced ~200ms

apps/editor/CLAUDE.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,14 +172,27 @@ already self-hosted via `dist/embed` — see `build.mjs`) as the events list
172172
view, but driven from the in-memory draft rather than a fetched feed:
173173
`main.ts`'s `refresh()` computes `toEventJson(state)` and calls
174174
`schedulePreviewUpdate()`, which debounces ~200ms then sets
175-
`previewWidget.events = [event]`. This works because
175+
`previewWidget.events = events`. This works because
176176
`oteJsonToPreviewFeed` (`packages/preview-feed`) treats every event field as
177177
optional and only ever throws if its input isn't shaped like `{ events:
178178
[...] }` — never true here — so the preview renders fine even for a blank
179179
new-event draft or mid-edit bulk-edit template. There is deliberately no
180180
"wait until the draft is schema-valid" gate; if you're tempted to add one,
181181
it isn't needed and would just make the preview lag behind typing.
182182

183+
`events` is `[toEventJson(state)]` (one card) only when `getRecurrenceSeries()`
184+
is empty. Once one or more "+ Add recurrence" rows exist, `refresh()` expands
185+
them the same way `proposeOrGenerate()` does at Review & submit time
186+
(`buildRecurringEvents(s, expandRecurrenceDates(s.rule))` per row, flattened)
187+
and previews every occurrence instead — otherwise the preview would keep
188+
showing just the shared template while the organizer builds a series, which
189+
is exactly the state that's about to disappear once Review & submit expands
190+
it for real. `getRecurrenceSeries` reads `renderForm`'s live recurrence-row
191+
state (via its own `getSeries` closure) and only exists in the normal
192+
single-event render path — `renderForm` never wires it up in bulk-edit mode
193+
(`bulkEditChecklist` set), so it stays `() => []` there and bulk edit keeps
194+
previewing the shared template alone, same as before.
195+
183196
## OTE has no recurrence-rule concept
184197

185198
The spec is explicit: one document per occurrence, always ("un documento

apps/editor/src/main.ts

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -889,22 +889,35 @@ async function startEditor(repo: string | null): Promise<void> {
889889
let draftValid = false;
890890

891891
// Debounced so a fast typist doesn't force a full shadow-DOM re-render on
892-
// every keystroke; the preview always reflects `state` as of the most
893-
// recent refresh() call, including mid-edit while bulk-editing a series
894-
// template — toEventJson() never throws on a partial/blank event (see
895-
// packages/preview-feed's tolerant field handling), so no separate
896-
// "wait until valid" gate is needed here.
892+
// every keystroke; the preview always reflects `state` (and, once one or
893+
// more recurrence rows exist, every occurrence they'd generate) as of the
894+
// most recent refresh() call — toEventJson() never throws on a
895+
// partial/blank event (see packages/preview-feed's tolerant field
896+
// handling), so no separate "wait until valid" gate is needed here.
897897
let previewTimer: ReturnType<typeof setTimeout> | undefined;
898-
function schedulePreviewUpdate(event: OteEvent): void {
898+
function schedulePreviewUpdate(events: OteEvent[]): void {
899899
clearTimeout(previewTimer);
900900
previewTimer = setTimeout(() => {
901-
previewWidget.events = [event] as unknown as OriginalOteEvent[];
901+
previewWidget.events = events as unknown as OriginalOteEvent[];
902902
}, 200);
903903
}
904904

905905
function refresh(): boolean {
906906
const event = toEventJson(state);
907-
schedulePreviewUpdate(event);
907+
// "+ Add recurrence" rows (getRecurrenceSeries, wired from renderForm)
908+
// aren't reflected in `state` itself — they only get expanded into real
909+
// occurrences at Review & submit time (proposeOrGenerate, below). The
910+
// preview reuses that same expansion (buildRecurringEvents/
911+
// expandRecurrenceDates) so it shows the whole series being built
912+
// instead of just the shared template with one date. Empty in bulk-edit
913+
// mode too (renderForm never wires recurrence rows there), so this
914+
// falls through to the single-event preview as before.
915+
const series = getRecurrenceSeries();
916+
schedulePreviewUpdate(
917+
series.length > 0
918+
? series.flatMap((s) => buildRecurringEvents(s, expandRecurrenceDates(s.rule)) as unknown as OteEvent[])
919+
: [event],
920+
);
908921

909922
// Bulk-edit template: id/slug/startDate are deliberately blank (see
910923
// buildBulkEditTemplate) — the normal required-field validation would

0 commit comments

Comments
 (0)