refactor Design the workout view model

Add the Workout DTO tree (slot, movement, and summary state) that the workout view will consume, so the controller can decide the pre-exhaust vs single-slot form shape and the presenter renders movements without matching on the prescription's delivery. Wiring the workout presenter and handlers onto it is the next step; the type is in place and compiles.

Commit
90f5ff22ad890c30a7da51fb2277ced6b29d918b
Author
Marius Peter <dev@marius-peter.com>
Author date
Committer
Marius Peter <dev@marius-peter.com>
Committer date
lib/web/view_model.ml
index 4bdbf125..d9ff3a12 100644..100644
@@ -77,3 +77,42 @@
77 77 (** The overview while no workout is in progress. The recovery policy has
78 78 already decided [gate] in the use case; the page only renders it. *)
79 79 end
80 Added:
81 Added: module Workout = struct
82 Added: type movement = {
83 Added: name : string; (** The exercise name shown for this input row. *)
84 Added: load_field : string; (** Form field name for the load input. *)
85 Added: reps_field : string; (** Form field name for the reps input. *)
86 Added: reps_label : string;
87 Added: load_value : string option;
88 Added: (** Pre-fill when correcting a recorded slot. *)
89 Added: reps_value : string option;
90 Added: }
91 Added: (** One input row of a slot's record/correction form. The controller emits one
92 Added: movement for a single-exercise slot and two for a pre-exhaust pair, so the
93 Added: presenter renders whatever movements it is given and never inspects the
94 Added: prescription's [delivery] shape itself. *)
95 Added:
96 Added: type slot = {
97 Added: index : int;
98 Added: label : string; (** Exercise label for the selector option and heading. *)
99 Added: movements : movement list;
100 Added: recorded_summary : string option;
101 Added: (** [Some description] once the slot is filled; [None] while
102 Added: outstanding. Drives the recorded/outstanding branch without an
103 Added: entity. *)
104 Added: }
105 Added:
106 Added: type t = {
107 Added: name : string; (** The workout (prescription) name, for the page title. *)
108 Added: slots : slot list;
109 Added: active_slot : int;
110 Added: started_at_unix : int; (** Workout start, for the elapsed timer. *)
111 Added: overridden : bool; (** Begun before recovery finished. *)
112 Added: all_recorded : bool; (** Every prescribed slot has a record. *)
113 Added: }
114 Added: (** A workout view: the slot the trainee is on, the record/correction state of
115 Added: each slot, and the timer and override facts. Carries no Evidence or
116 Added: Prescription entity. Extension/ending selection stays in the presenter
117 Added: form, since its option set is fixed UI vocabulary, not domain data. *)
118 Added: end