ENGLISH·COURSE API
    Preparing search index...
    • Client hook: reads and writes the playback position for one lesson.

      Parameters

      • lessonId: string & $brand<"LessonId">

        The lesson whose position is being tracked

      • Optionalrepository: FlushablePlaybackPositions

        Overrides the adapter; tests inject a fake here. A port without flush methods has nothing to flush.

      Returns PlaybackPositionHandle

      get, set, flush and flushWithBeacon

      This hook is the client's composition root for playback persistence — the one place allowed to name a concrete adapter, the same role the learner dependencies play on the server. Everything downstream of it sees only the PlaybackPositionRepository port.

      The default adapter shows every position at once on every progress bar (through the learner store) and saves it for the signed-in learner at most every ten seconds per lesson; flush and flushWithBeacon send what is still waiting. Writes are validated by the PlaybackPosition value object first: a <video> detached mid-teardown reports NaN for currentTime, and that must never be saved.

      Reads go through the getPlaybackPosition use case rather than calling the adapter, so the domain owns the "no entry yet" semantics.

      The returned object is memoized on the lesson, so consumers can list it in a useEffect dependency array without retriggering on every render.

      Browser-side only — do NOT call from a Server Component or Server Action.

      const position = usePlaybackPosition(lessonId);

      const saved = await position.get(); // seek the player to this
      await position.set(videoRef.current.currentTime);