open Dream_html
open Page_kit
open Page_shell
(* The review of a provisional import batch. It renders the parse warnings, then
each workout with its sets, blockers, and forms. Every form is a plain POST
carrying its CSRF token, so cleaning and promotion need no script. The page
names only the view model: the controller has already phrased set types,
blockers, and warnings, so no core entity crosses the boundary here. *)
let import_review request ~viewer (vm : View_model.Import_review.t) =
let warnings_block =
match vm.View_model.Import_review.warnings with
| [] -> []
| warnings ->
[
tag "section"
[ class_ "import-warnings" ]
[
tag "h2" [] [ txt "Dropped rows" ];
tag "ul" []
(List.map
(fun (w : View_model.Import_warning.t) ->
tag "li" []
[
txt "Row %d: %s" w.View_model.Import_warning.row
w.View_model.Import_warning.detail;
])
warnings);
];
]
in
(* One row per set. A mapped set shows the catalog name it resolves to. *)
let set_row (s : View_model.Import_set.t) =
let mapping =
match s.View_model.Import_set.mapping with
| Some name -> Printf.sprintf " → %s" name
| None -> " → unmapped"
in
tag "li" []
[
txt "Row %d: %s (%s) %s kg × %s reps%s" s.View_model.Import_set.row
s.View_model.Import_set.exercise_name s.View_model.Import_set.set_type
s.View_model.Import_set.weight s.View_model.Import_set.reps mapping;
]
in
(* One mapping form per distinct source name in the workout. The source name
is fixed by a hidden field; the trainee supplies the catalog exercise id. *)
let mapping_form batch_id workout_id source_name =
tag "form"
[
action Routes.import_map batch_id workout_id;
post_form;
class_ "import-map-form";
]
[
Dream_html.csrf_tag request;
void "input"
[
type_ "hidden";
name "source_name";
Dream_html.string_attr "value" "%s" source_name;
];
tag "div"
[ class_ "field" ]
[
tag "label" [] [ txt "Map %s to exercise id" source_name ];
void "input" [ type_ "text"; name "exercise_id"; required ];
];
void "input" [ type_ "submit"; value "Map exercise" ];
]
in
let confirm_form batch_id workout_id acknowledgement =
tag "form"
[
action Routes.import_confirm batch_id workout_id;
post_form;
class_ "import-confirm-form";
]
[
Dream_html.csrf_tag request;
tag "div"
[ class_ "field" ]
[
tag "label" [] [ txt "Confirm normal sets" ];
void "input"
([ type_ "text"; name "acknowledgement"; required ]
@
match acknowledgement with
| Some ack -> [ Dream_html.string_attr "value" "%s" ack ]
| None -> []);
];
void "input" [ type_ "submit"; value "Confirm normal sets" ];
]
in
let promote_workout_form batch_id workout_id =
tag "form"
[
action Routes.import_promote_workout batch_id workout_id;
post_form;
class_ "import-promote-workout-form";
]
[
Dream_html.csrf_tag request;
void "input" [ type_ "submit"; value "Promote workout" ];
]
in
let blockers_block (w : View_model.Import_workout.t) =
match w.View_model.Import_workout.blockers with
| [] -> [ tag "p" [ class_ "import-ready" ] [ txt "Ready to promote." ] ]
| blockers ->
[
tag "p" [] [ txt "Blocked:" ];
tag "ul"
[ class_ "import-blockers" ]
(List.map (fun b -> tag "li" [] [ txt "%s" b ]) blockers);
]
in
let workout_section (w : View_model.Import_workout.t) =
let batch_id = vm.View_model.Import_review.batch_id in
let workout_id = w.View_model.Import_workout.id in
(* Every distinct source name, in first-appearance order. *)
let source_names =
List.fold_left
(fun acc (s : View_model.Import_set.t) ->
let n = s.View_model.Import_set.exercise_name in
if List.mem n acc then acc else acc @ [ n ])
[] w.View_model.Import_workout.sets
in
tag "section"
[ class_ "import-workout" ]
([
tag "h2" [] [ txt "%s" w.View_model.Import_workout.title ];
tag "ul"
[ class_ "import-sets" ]
(List.map set_row w.View_model.Import_workout.sets);
]
@ blockers_block w
@ List.map (mapping_form batch_id workout_id) source_names
@ [
confirm_form batch_id workout_id
w.View_model.Import_workout.acknowledgement;
promote_workout_form batch_id workout_id;
])
in
let batch_promote_form =
tag "form"
[
action Routes.import_promote_batch vm.View_model.Import_review.batch_id;
post_form;
class_ "import-promote-batch-form";
]
[
Dream_html.csrf_tag request;
void "input" [ type_ "submit"; value "Promote whole batch" ];
]
in
html_page ~viewer ~request ~active:"profile" "Import review"
([ tag "h1" [] [ txt "Import review" ] ]
@ warnings_block
@ List.map workout_section vm.View_model.Import_review.workouts
@ [ batch_promote_form ])