[OCaml] High Intensity Training Online
1
open Dream_html
2
open Page_kit
3
open Page_shell
4
5
(* The authenticated application feedback page. It keeps writing and reviewing
6
feedback in separate tabs, while both tabs remain plain links for no-script
7
use and progressive enhancement. *)
8
9
let app_feedback_form request ?error () =
10
let error_block =
11
match error with None -> [] | Some message -> [ alert message ]
12
in
13
tag "form"
14
[
15
action Routes.submit_app_feedback;
16
post_form;
17
class_ "app-feedback-form";
18
Dream_html.attr "data-hito-app-form";
19
]
20
(Dream_html.csrf_tag request
21
:: tag "label"
22
[ Dream_html.string_attr "for" "app-feedback-message" ]
23
[ txt "Your feedback" ]
24
:: tag "textarea"
25
[
26
name "message";
27
id "app-feedback-message";
28
Dream_html.string_attr "rows" "8";
29
required;
30
Dream_html.string_attr "placeholder"
31
"Tell us what works well or what needs attention.";
32
]
33
[]
34
:: error_block
35
@ [ void "input" [ type_ "submit"; value "Submit feedback" ] ])
36
37
let app_feedback_vote_form request (report : View_model.App_feedback.t) =
38
if report.viewer_owns then
39
tag "p" [ class_ "app-feedback-own" ] [ txt "Your feedback" ]
40
else
41
let label =
42
if report.viewer_upvoted then "Upvoted"
43
else Printf.sprintf "Upvote (%d)" report.upvotes
44
in
45
let attrs =
46
[
47
action Routes.upvote_app_feedback report.id;
48
post_form;
49
class_ "app-feedback-vote";
50
Dream_html.attr "data-hito-app-form";
51
]
52
in
53
let attrs =
54
if report.viewer_upvoted then Dream_html.attr "disabled" :: attrs
55
else attrs
56
in
57
tag "form" attrs
58
[
59
Dream_html.csrf_tag request;
60
void "input"
61
[ type_ "submit"; Dream_html.string_attr "value" "%s" label ];
62
]
63
64
let app_feedback_edit_form request (report : View_model.App_feedback.t) =
65
tag "form"
66
[
67
action Routes.edit_app_feedback report.id;
68
post_form;
69
class_ "app-feedback-edit-form";
70
Dream_html.attr "data-hito-app-form";
71
]
72
[
73
Dream_html.csrf_tag request;
74
tag "label"
75
[ Dream_html.string_attr "for" "app-feedback-edit-%s" report.id ]
76
[ txt "Edit feedback" ];
77
tag "textarea"
78
[
79
name "message";
80
Dream_html.string_attr "id" "app-feedback-edit-%s" report.id;
81
Dream_html.string_attr "rows" "4";
82
required;
83
]
84
[ txt "%s" report.message ];
85
void "input" [ type_ "submit"; value "Save edit" ];
86
]
87
88
let app_feedback_remove_form request (report : View_model.App_feedback.t) =
89
tag "form"
90
[
91
action Routes.remove_app_feedback report.id;
92
post_form;
93
class_ "app-feedback-remove-form";
94
Dream_html.attr "data-hito-app-form";
95
]
96
[
97
Dream_html.csrf_tag request;
98
void "input" [ type_ "submit"; value "Remove feedback" ];
99
]
100
101
let app_feedback_actions request (report : View_model.App_feedback.t) =
102
if report.viewer_owns then
103
tag "div"
104
[ class_ "app-feedback-actions" ]
105
[
106
app_feedback_edit_form request report;
107
app_feedback_remove_form request report;
108
]
109
else
110
tag "div"
111
[ class_ "app-feedback-actions" ]
112
[ app_feedback_vote_form request report ]
113
114
let app_feedback request ?workout_started ~viewer ?(tab = `Write) ?error reports
115
=
116
let panel =
117
match tab with
118
| `Write ->
119
[
120
tag "h2" [] [ txt "Write feedback" ];
121
tag "p" []
122
[ txt "Tell us about your experience using the application." ];
123
app_feedback_form request ?error ();
124
]
125
| `Submitted ->
126
[
127
tag "h2" [] [ txt "Submitted feedback" ];
128
(if reports = [] then
129
tag "p" []
130
[ txt "You have not submitted any application feedback." ]
131
else
132
tag "ul"
133
[ class_ "app-feedback-list" ]
134
(List.map
135
(fun (report : View_model.App_feedback.t) ->
136
tag "li" []
137
[
138
tag "p"
139
[ class_ "app-feedback-author" ]
140
[
141
txt "%s — %d contributions" report.author
142
report.contributions;
143
];
144
tag "time"
145
[
146
class_ "app-feedback-time";
147
Dream_html.string_attr "datetime" "%s"
148
report.submitted_at;
149
]
150
[ txt "%s" report.submitted_at ];
151
tag "p"
152
[ class_ "app-feedback-message" ]
153
[ txt "%s" report.message ];
154
tag "p"
155
[ class_ "app-feedback-upvotes" ]
156
[ txt "Upvotes: %d" report.upvotes ];
157
app_feedback_actions request report;
158
])
159
reports));
160
]
161
in
162
html_page ~viewer ~request ~active:"app-feedback" ?workout_started
163
"App Feedback"
164
([
165
tag "h1" [] [ txt "App Feedback" ];
166
tag "p" [] [ txt "Help us improve hito by sharing your experience." ];
167
link_tabs ~aria_label:"App feedback views"
168
~active:
169
(match tab with `Write -> "write" | `Submitted -> "submitted")
170
[
171
("write", "Write feedback", "/app-feedback?tab=write");
172
("submitted", "Submitted feedback", "/app-feedback?tab=submitted");
173
];
174
]
175
@ panel)
176