feat Add workout date and refine type

Commit
81dd7e1ef46aa449640b46010da9f617c2c9fa09
Author
Marius Peter <dev@marius-peter.com>
Author date
Committer
Marius Peter <dev@marius-peter.com>
Committer date
Changed files
lib/presenter/pages_workout.ml
index 790a1fbd..b8dade46 100644..100644
@@ -356,7 +356,10 @@
356 356 Dream_html.attr "data-hito-workout-content";
357 357 ]
358 358 else [])
359 Removed: ([ tag "h1" [] [ txt "%s" vm.name ] ]
359 Added: ([
360 Added: tag "h1" [] [ txt "%s" vm.name ];
361 Added: tag "h2" [ class_ "workout-date" ] [ txt "%s" vm.date ];
362 Added: ]
360 363 @ slots @ complete_note @ finish_section
361 364 @
362 365 if enhanced then
lib/presenter/view_model.ml
index 5151f904..0060f58c 100644..100644
@@ -131,6 +131,8 @@
131 131
132 132 type t = {
133 133 name : string; (** The workout (prescription) name, for the page title. *)
134 Added: date : string;
135 Added: (** Workout start date, pre-formatted as "day month year" in UTC. *)
134 136 slots : slot list;
135 137 active_slot : int;
136 138 started_at_unix : int; (** Workout start, for the elapsed timer. *)
lib/web/assets/hito.css
index 75c15dc7..473ad218 100644..100644
@@ -930,6 +930,12 @@
930 930 .in-progress h1 { margin: 0.35rem 0; }
931 931 .in-progress p { margin: 0; }
932 932
933 Added: .workout-date {
934 Added: margin: 0 0 1.25rem;
935 Added: color: var(--ink);
936 Added: font: 500 var(--font-size-h2)/1.25 var(--sans);
937 Added: }
938 Added:
933 939 /* The exercise accordion uses one <details> per prescription slot. They share
934 940 a [name], so the browser keeps exactly one open without script. The summary
935 941 holds the slot's level-two heading and a plus or minus marker. The heading
@@ -969,6 +975,9 @@
969 975 align-items: baseline;
970 976 gap: 0.6rem;
971 977 margin: 0;
978 Added: font-size: var(--font-size-h3);
979 Added: line-height: 1.25;
980 Added: font-weight: 600;
972 981 }
973 982 .slot-heading .slot-number { color: var(--muted-ink); }
974 983 .slot-heading .slot-label-done {
lib/web/handlers_kit.ml
index 7c5d2c1b..ffb2fc9a 100644..100644
@@ -83,6 +83,32 @@
83 83 Printf.sprintf "%04d-%02d-%02d" (tm.Unix.tm_year + 1900)
84 84 (tm.Unix.tm_mon + 1) tm.Unix.tm_mday
85 85
86 Added: let ordinal_suffix day =
87 Added: if day mod 100 >= 11 && day mod 100 <= 13 then "th"
88 Added: else match day mod 10 with 1 -> "st" | 2 -> "nd" | 3 -> "rd" | _ -> "th"
89 Added:
90 Added: let month_name = function
91 Added: | 1 -> "January"
92 Added: | 2 -> "February"
93 Added: | 3 -> "March"
94 Added: | 4 -> "April"
95 Added: | 5 -> "May"
96 Added: | 6 -> "June"
97 Added: | 7 -> "July"
98 Added: | 8 -> "August"
99 Added: | 9 -> "September"
100 Added: | 10 -> "October"
101 Added: | 11 -> "November"
102 Added: | 12 -> "December"
103 Added: | _ -> ""
104 Added:
105 Added: let utc_long_date seconds =
106 Added: let tm = Unix.gmtime (float_of_int seconds) in
107 Added: let day = tm.Unix.tm_mday in
108 Added: Printf.sprintf "%d%s %s %d" day (ordinal_suffix day)
109 Added: (month_name (tm.Unix.tm_mon + 1))
110 Added: (tm.Unix.tm_year + 1900)
111 Added:
86 112 let utc_datetime seconds =
87 113 let tm = Unix.gmtime (float_of_int seconds) in
88 114 Printf.sprintf "%04d-%02d-%02d %02d:%02d" (tm.Unix.tm_year + 1900)
@@ -449,6 +475,10 @@
449 475 in
450 476 {
451 477 name = Prescription.Workout.name prescription;
478 Added: date =
479 Added: utc_long_date
480 Added: (Recovery.timestamp_to_unix_seconds
481 Added: (Evidence.Workout.started_at workout));
452 482 slots = List.mapi slot_view prescribed_slots;
453 483 active_slot;
454 484 started_at_unix =
test/web/workout.ml
index 7a5d4ed5..029086e1 100644..100644
@@ -8,7 +8,8 @@
8 8 ( "a signed-in trainee selects a routine and begins a workout",
9 9 `Quick,
10 10 fun () ->
11 Removed: let c, repo = client_with_repo () in
11 Added: let c, now, repo = clocked_client () in
12 Added: now := day 10;
12 13 let _ = register c ~username:"lifter" ~password:"heavyduty1" in
13 14 let trainee = the_trainee repo ~username:"lifter" in
14 15 let token = Option.get (csrf_token (body (get c "/"))) in
@@ -30,6 +31,11 @@
30 31 Alcotest.(check int)
31 32 "the workout view is served" 200
32 33 (status (get c "/workout"));
34 Added: let workout_page = body (get c "/workout") in
35 Added: Alcotest.(check bool)
36 Added: "the workout date is shown" true
37 Added: (Option.is_some
38 Added: (index_from ~needle:"11th January 1970" workout_page 0));
33 39 (* The static workout client asset is served. *)
34 40 let asset = get c "/assets/workout-client.js" in
35 41 Alcotest.(check int) "serves the workout client" 200 (status asset)