Skip to content

fix: address review findings on the slide-execution hooks - #11

Merged
tuj merged 1 commit into
feature/template-cleanupsfrom
fix/template-hook-review-followups
Sep 1, 2026
Merged

fix: address review findings on the slide-execution hooks#11
tuj merged 1 commit into
feature/template-cleanupsfrom
fix/template-hook-review-followups

Conversation

@turegjorup

Copy link
Copy Markdown

Review follow-ups for #5, plus the scheduling doc and the template skill update. Targets feature/template-cleanups, not release/3.0.0.

Hooks

  • Empty entries now finish the slide — moved into useMultipleEntrySlideExecution, declared per template via emptyEntriesDuration (existing timings kept: 1s, 5s for news-feed, 2s for slideshow). Each template had its own copy of the timer, which is the duplication the extraction removes elsewhere; a new template that omits it locks the playlist.
  • Cycling starts when entries arrive after run — the effect keyed only on run, so a feed resolving late was skipped for that rotation.
  • The hook returns the clamped entryDurationposter, instagram-feed and slideshow derived their fade timers from the raw prop, so duration: 0 left the hook cycling at 15s while the fade fired immediately and the entry sat faded out. clampDuration extracted to slide-utils/duration.js so both clocks agree.
  • Dropped durationRef from useBaseSlideExecution — read once, synchronously, in an effect recreated on every run change, so it prevented no staleness the comment claimed.

Templates

  • image-text: images/duration mirrored into refs in a layout effect instead of during render.
  • video: slide/slideDone read through refs, since finish() runs from a guard timer or media event; element paused on teardown so a preview toggling run stops making noise.

Tests

116 passing, 22 files. New: clampDuration, empty-feed fallback across all five consumers, late-arriving entries, the exposed clamped duration, fade-timer alignment, image-text cycling, video pause and slideDone routing.

The fade-timer and video cases were confirmed red against this branch before the fix. The image-text cases pass either way — they pin behaviour, since that change is behaviour-preserving.

vitest.config.js gains the svgr plugin from vite.config.js; without it an import X from "./x.svg" resolves to a data-URI string and any template importing an SVG throws in jsdom, so instagram-feed could not be tested at all.

Docs

  • docs/client-scheduling.md — content selection, rotation, and the slideDone contract. Also documents two things easy to miss: a staged list goes live immediately when nothing is playing (wraparound is the swap point only mid-rotation), and slides marked invalid are dropped by the region.
  • add-slide-template skill — the duration field must be named duration (the Admin's widget writes to a hardcoded id, so any other name diverges from what it displays), and the Admin stores ms while showing seconds.

Not addressed

  • useBaseSlideExecution.js / useMultipleEntrySlideExecution.js are camelCase while the repo uses kebab-case, including these hooks' own test files. Left alone — renaming churns every import.
  • checkForEmptyContent reads a stale list (region.slide vs region.slides); noted in the doc, fix belongs elsewhere.

Follow-ups from review of the hook extraction, plus the scheduling doc and the
template skill update.

Hooks:
- Move the empty-entries fallback into useMultipleEntrySlideExecution, declared
  per template via emptyEntriesDuration. Each template had its own copy of the
  timer, which is the duplication the extraction set out to remove: a new
  template that omits it locks the playlist.
- Start cycling when entries arrive after run turned truthy. The effect keyed
  only on run, so a feed resolving late was skipped for that rotation.
- Return the clamped entryDuration. poster, instagram-feed and slideshow derived
  their fade timers from the raw prop, so a duration of 0 left the hook cycling
  at 15s while the fade fired immediately.
- Extract clampDuration into slide-utils/duration.js so both clocks agree.
- Drop durationRef from useBaseSlideExecution: it is read once, synchronously,
  in an effect recreated on every run change, so it prevented no staleness.

Templates:
- image-text: mirror images/duration into refs in a layout effect instead of
  during render.
- video: read slide/slideDone through refs, since finish() runs from a guard
  timer or media event; pause the element on teardown so a preview that toggles
  run does not keep playing audio.

Tests: 116 pass, 22 files. New coverage for clampDuration, the empty-feed
fallback across all five consumers, late-arriving entries, the exposed clamped
duration, fade-timer alignment, image-text cycling, and video pause/slideDone.
The fade-timer and video cases were confirmed red against this branch before
the fix; the image-text ones pin behaviour rather than catching a bug.

vitest.config.js gets the svgr plugin from vite.config.js, without which any
template importing an SVG throws in jsdom and cannot be tested at all.

Docs:
- docs/client-scheduling.md — content selection, rotation and the slideDone
  contract, including the immediate go-live path when nothing is playing, the
  invalid-slide filter, and the stale-list bug in checkForEmptyContent.
- add-slide-template skill — the duration field must be named `duration` (the
  Admin writes to a hardcoded id) and the Admin stores ms while showing seconds.
@tuj
tuj merged commit 59d23b4 into feature/template-cleanups Sep 1, 2026
20 checks passed
@tuj
tuj deleted the fix/template-hook-review-followups branch September 1, 2026 09:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants