[Pharo] Personal fitness tracker web app.
Add workout logbook viewer.
Changed files
- src/MyFitnessTracker-Web/MFTHomePage.class.st
- src/MyFitnessTracker-Web/MFTLogBookViewerComponent.class.st
- src/MyFitnessTracker-Web/MFTSetGroupLogEditorComponent.class.st
- src/MyFitnessTracker-Web/MFTSetGroupLogViewerComponent.class.st
- src/MyFitnessTracker-Web/MFTStatusComponent.class.st
- src/MyFitnessTracker-Web/MFTWorkoutLogEditorComponent.class.st
- src/MyFitnessTracker-Web/MFTWorkoutLogEditorPage.class.st
- src/MyFitnessTracker-Web/MFTWorkoutLogViewerComponent.class.st
- src/MyFitnessTracker-Web/MFTWorkoutPrescriptionViewerComponent.class.st
src/MyFitnessTracker-Web/MFTHomePage.class.st
@@ -3,8 +3,9 @@
3
3
#superclass : 'MFTPage',
4
4
#instVars : [
5
5
'statusComponent',
6
Added:
'homePageActionsComponent',
6
7
'nextWorkoutComponent',
7
Removed:
'homePageActionsComponent'
8
Added:
'previousWorkoutLogsComponent'
8
9
],
9
10
#category : 'MyFitnessTracker-Web-Components',
10
11
#package : 'MyFitnessTracker-Web',
@@ -23,11 +24,14 @@
23
24
{ #category : 'initialization' }
24
25
MFTHomePage >> initialize [
25
26
27
Added:
| trainee |
28
Added:
trainee := self session user trainee.
29
Added:
26
30
super initialize.
27
31
statusComponent := MFTStatusComponent new.
28
32
homePageActionsComponent := MFTMainActionsComponent new
29
33
onLogWorkout: [
30
Removed:
| trainee workoutLog |
34
Added:
| workoutLog |
31
35
trainee := self session user trainee.
32
36
workoutLog := self call:
33
37
(MFTWorkoutLogEditorPage
@@ -38,7 +42,10 @@
38
42
trainee logWorkout: workoutLog ] ];
39
43
yourself.
40
44
nextWorkoutComponent := MFTWorkoutPrescriptionViewerComponent new
41
Removed:
heading: 'Next workout'
45
Added:
heading: 'Next workout'.
46
Added:
previousWorkoutLogsComponent := MFTLogBookViewerComponent new
47
Added:
logBook: trainee logBook;
48
Added:
heading: 'Previous workouts'
42
49
]
43
50
44
51
{ #category : 'rendering' }
@@ -56,7 +63,8 @@
56
63
html
57
64
render: statusComponent;
58
65
render: homePageActionsComponent;
59
Removed:
render: nextWorkoutComponent ]
66
Added:
render: nextWorkoutComponent;
67
Added:
render: previousWorkoutLogsComponent ]
60
68
]
61
69
62
70
{ #category : 'accessing' }
src/MyFitnessTracker-Web/MFTLogBookViewerComponent.class.st
@@ -0,0 +1,55 @@
1
Added:
Class {
2
Added:
#name : 'MFTLogBookViewerComponent',
3
Added:
#superclass : 'WAComponent',
4
Added:
#instVars : [
5
Added:
'logBook',
6
Added:
'logBookItemComponents',
7
Added:
'heading'
8
Added:
],
9
Added:
#category : 'MyFitnessTracker-Web-Components',
10
Added:
#package : 'MyFitnessTracker-Web',
11
Added:
#tag : 'Components'
12
Added:
}
13
Added:
14
Added:
{ #category : 'accessing' }
15
Added:
MFTLogBookViewerComponent class >> forLogBook: aMFTWorkoutLogBook [
16
Added:
17
Added:
^ self new logBook: aMFTWorkoutLogBook
18
Added:
]
19
Added:
20
Added:
{ #category : 'rendering' }
21
Added:
MFTLogBookViewerComponent >> children [
22
Added:
23
Added:
^ logBookItemComponents
24
Added:
]
25
Added:
26
Added:
{ #category : 'rendering' }
27
Added:
MFTLogBookViewerComponent >> heading: aString [
28
Added:
29
Added:
heading := aString
30
Added:
]
31
Added:
32
Added:
{ #category : 'rendering' }
33
Added:
MFTLogBookViewerComponent >> initialize [
34
Added:
35
Added:
super initialize
36
Added:
]
37
Added:
38
Added:
{ #category : 'accessing' }
39
Added:
MFTLogBookViewerComponent >> logBook: aMFTWorkoutLogBook [
40
Added:
41
Added:
logBook := aMFTWorkoutLogBook.
42
Added:
]
43
Added:
44
Added:
{ #category : 'rendering' }
45
Added:
MFTLogBookViewerComponent >> renderContentOn: html [
46
Added:
47
Added:
logBookItemComponents := logBook workoutLogs collect: [ :each |
48
Added:
MFTWorkoutLogViewerComponent
49
Added:
forWorkoutLog: each ].
50
Added:
51
Added:
html heading
52
Added:
level: 2;
53
Added:
with: heading.
54
Added:
logBookItemComponents do: [ :each | html render: each ]
55
Added:
]
src/MyFitnessTracker-Web/MFTSetGroupLogEditorComponent.class.st
@@ -28,7 +28,7 @@
28
28
with: 'Save' ]
29
29
]
30
30
31
Removed:
{ #category : 'rendering' }
31
Added:
{ #category : 'as yet unclassified' }
32
32
MFTSetGroupLogEditorComponent >> renderSetLogEditorOn: html setLog: setLog [
33
33
34
34
html heading
src/MyFitnessTracker-Web/MFTSetGroupLogViewerComponent.class.st
@@ -2,7 +2,8 @@
2
2
#name : 'MFTSetGroupLogViewerComponent',
3
3
#superclass : 'WAComponent',
4
4
#instVars : [
5
Removed:
'setGroupLog'
5
Added:
'setGroupLog',
6
Added:
'isEditable'
6
7
],
7
8
#category : 'MyFitnessTracker-Web-Components',
8
9
#package : 'MyFitnessTracker-Web',
@@ -18,6 +19,25 @@
18
19
]
19
20
20
21
{ #category : 'rendering' }
22
Added:
MFTSetGroupLogViewerComponent >> beEditable [
23
Added:
24
Added:
isEditable := true
25
Added:
]
26
Added:
27
Added:
{ #category : 'rendering' }
28
Added:
MFTSetGroupLogViewerComponent >> initialize [
29
Added:
30
Added:
super initialize.
31
Added:
isEditable := false
32
Added:
]
33
Added:
34
Added:
{ #category : 'rendering' }
35
Added:
MFTSetGroupLogViewerComponent >> isEditable [
36
Added:
37
Added:
isEditable
38
Added:
]
39
Added:
40
Added:
{ #category : 'rendering' }
21
41
MFTSetGroupLogViewerComponent >> renderContentOn: html [
22
42
23
43
| completelyLogged buttonLabel |
@@ -30,14 +50,15 @@
30
50
completelyLogged
31
51
ifTrue: [ self renderSetGroupLogDataOn: html ]
32
52
ifFalse: [ self renderSetGroupLogExercisesOn: html ].
33
Removed:
html anchor
34
Removed:
callback: [
35
Removed:
| editedLog |
36
Removed:
editedLog := self call:
37
Removed:
(MFTSetGroupLogEditorComponent forSetGroupLog:
38
Removed:
setGroupLog).
39
Removed:
editedLog ifNotNil: [ setGroupLog := editedLog ] ];
40
Removed:
with: buttonLabel ]
53
Added:
isEditable ifTrue: [
54
Added:
html anchor
55
Added:
callback: [
56
Added:
| editedLog |
57
Added:
editedLog := self call:
58
Added:
(MFTSetGroupLogEditorComponent forSetGroupLog:
59
Added:
setGroupLog).
60
Added:
editedLog ifNotNil: [ setGroupLog := editedLog ] ];
61
Added:
with: buttonLabel ] ]
41
62
]
42
63
43
64
{ #category : 'rendering' }
src/MyFitnessTracker-Web/MFTStatusComponent.class.st
@@ -14,6 +14,10 @@
14
14
15
15
html section: [
16
16
html definitionList: [
17
Added:
trainee logBook durationSinceLastWorkout ifNotNil: [
18
Added:
html definitionTerm: 'Hours since last workout'.
19
Added:
html definitionData:
20
Added:
trainee logBook durationSinceLastWorkout asHours rounded asString ].
17
21
html definitionTerm: 'Recovery status'.
18
22
html definitionData: (trainee isRecovered
19
23
ifTrue: [ 'Ready to train again' ]
src/MyFitnessTracker-Web/MFTWorkoutLogEditorComponent.class.st
@@ -0,0 +1,130 @@
1
Added:
Class {
2
Added:
#name : 'MFTWorkoutLogEditorComponent',
3
Added:
#superclass : 'WAComponent',
4
Added:
#instVars : [
5
Added:
'workoutLog',
6
Added:
'setGroupLogComponents',
7
Added:
'onSaveWorkout',
8
Added:
'onDiscardWorkout'
9
Added:
],
10
Added:
#category : 'MyFitnessTracker-Web-Components',
11
Added:
#package : 'MyFitnessTracker-Web',
12
Added:
#tag : 'Components'
13
Added:
}
14
Added:
15
Added:
{ #category : 'as yet unclassified' }
16
Added:
MFTWorkoutLogEditorComponent class >> forWorkoutLog: aMFTWorkoutLog [
17
Added:
18
Added:
^ self new
19
Added:
workoutLog: aMFTWorkoutLog;
20
Added:
yourself
21
Added:
]
22
Added:
23
Added:
{ #category : 'as yet unclassified' }
24
Added:
MFTWorkoutLogEditorComponent >> children [
25
Added:
26
Added:
^ setGroupLogComponents
27
Added:
]
28
Added:
29
Added:
{ #category : 'as yet unclassified' }
30
Added:
MFTWorkoutLogEditorComponent >> initialize [
31
Added:
32
Added:
super initialize.
33
Added:
setGroupLogComponents := OrderedCollection new
34
Added:
]
35
Added:
36
Added:
{ #category : 'as yet unclassified' }
37
Added:
MFTWorkoutLogEditorComponent >> onDiscardWorkout: aBlock [
38
Added:
39
Added:
onDiscardWorkout := aBlock
40
Added:
]
41
Added:
42
Added:
{ #category : 'as yet unclassified' }
43
Added:
MFTWorkoutLogEditorComponent >> onSaveWorkout: aBlock [
44
Added:
45
Added:
onSaveWorkout := aBlock
46
Added:
]
47
Added:
48
Added:
{ #category : 'rendering' }
49
Added:
MFTWorkoutLogEditorComponent >> renderContentOn: html [
50
Added:
51
Added:
html heading
52
Added:
level: 1;
53
Added:
with: 'Log Workout'.
54
Added:
html heading
55
Added:
level: 2;
56
Added:
with: workoutLog prescription canonicalName.
57
Added:
html form: [
58
Added:
self renderWorkoutLogMetadataOn: html.
59
Added:
setGroupLogComponents do: [ :each | html render: each ].
60
Added:
self renderFormActionsOn: html ]
61
Added:
]
62
Added:
63
Added:
{ #category : 'as yet unclassified' }
64
Added:
MFTWorkoutLogEditorComponent >> renderFormActionsOn: html [
65
Added:
66
Added:
html submitButton
67
Added:
callback: [ onSaveWorkout value ];
68
Added:
with: 'Save workout'.
69
Added:
70
Added:
html submitButton
71
Added:
callback: [ onDiscardWorkout value ];
72
Added:
with: 'Discard workout'
73
Added:
]
74
Added:
75
Added:
{ #category : 'as yet unclassified' }
76
Added:
MFTWorkoutLogEditorComponent >> renderWorkoutLogMetadataOn: html [
77
Added:
78
Added:
html fieldSet with: [
79
Added:
html div
80
Added:
class: 'mft-form-items-container';
81
Added:
with: [
82
Added:
html label
83
Added:
for: 'start-date';
84
Added:
with: 'Start'.
85
Added:
html span: [
86
Added:
html dateInput5
87
Added:
id: 'start-date';
88
Added:
value: Date today yyyymmdd;
89
Added:
callback: [ :value |
90
Added:
workoutLog startDate:
91
Added:
(Date readFrom: value pattern: 'yyyy-mm-dd') ].
92
Added:
html timeInput5
93
Added:
id: 'start-time';
94
Added:
value: workoutLog start asTime print24;
95
Added:
callback: [ :value |
96
Added:
workoutLog startTime: (Time fromString: value) ] ] ].
97
Added:
html div
98
Added:
class: 'mft-form-items-container';
99
Added:
with: [
100
Added:
html label
101
Added:
for: 'finish-date';
102
Added:
with: 'Finish'.
103
Added:
html span: [
104
Added:
html dateInput5
105
Added:
id: 'finish-date';
106
Added:
value: Date today yyyymmdd;
107
Added:
callback: [ :value |
108
Added:
workoutLog finishDate:
109
Added:
(Date readFrom: value pattern: 'yyyy-mm-dd') ].
110
Added:
html timeInput5
111
Added:
id: 'finish-time';
112
Added:
callback: [ :value |
113
Added:
value ifNotEmpty: [
114
Added:
workoutLog finishTime: (Time fromString: value) ] ] ] ] ]
115
Added:
]
116
Added:
117
Added:
{ #category : 'accessing' }
118
Added:
MFTWorkoutLogEditorComponent >> title [
119
Added:
120
Added:
^ 'Log workout'
121
Added:
]
122
Added:
123
Added:
{ #category : 'accessing' }
124
Added:
MFTWorkoutLogEditorComponent >> workoutLog: aMFTWorkoutLog [
125
Added:
126
Added:
workoutLog := aMFTWorkoutLog.
127
Added:
setGroupLogComponents := workoutLog setGroups collect: [ :setGroupLog |
128
Added:
(MFTSetGroupLogViewerComponent
129
Added:
forSetGroupLog: setGroupLog) beEditable ]
130
Added:
]
src/MyFitnessTracker-Web/MFTWorkoutLogEditorPage.class.st
@@ -2,8 +2,8 @@
2
2
#name : 'MFTWorkoutLogEditorPage',
3
3
#superclass : 'MFTPage',
4
4
#instVars : [
5
Removed:
'workoutLog',
6
Removed:
'setGroupLogComponents'
5
Added:
'workoutLogEditorComponent',
6
Added:
'workoutLog'
7
7
],
8
8
#category : 'MyFitnessTracker-Web-Components',
9
9
#package : 'MyFitnessTracker-Web',
@@ -15,6 +15,8 @@
15
15
16
16
^ self new
17
17
workoutLog: aMFTWorkoutLog;
18
Added:
workoutLogEditorComponent:
19
Added:
(MFTWorkoutLogEditorComponent forWorkoutLog: aMFTWorkoutLog);
18
20
yourself
19
21
]
20
22
@@ -32,86 +34,17 @@
32
34
{ #category : 'as yet unclassified' }
33
35
MFTWorkoutLogEditorPage >> children [
34
36
35
Removed:
^ setGroupLogComponents
37
Added:
^ { workoutLogEditorComponent }
36
38
]
37
39
38
Removed:
{ #category : 'initialization' }
39
Removed:
MFTWorkoutLogEditorPage >> initialize [
40
Removed:
41
Removed:
super initialize.
42
Removed:
setGroupLogComponents := OrderedCollection new
43
Removed:
]
44
Removed:
45
40
{ #category : 'rendering' }
46
41
MFTWorkoutLogEditorPage >> renderContentOn: html [
47
42
48
Removed:
self renderPageOn: html with: [
49
Removed:
html heading
50
Removed:
level: 1;
51
Removed:
with: 'Log Workout'.
52
Removed:
html heading
53
Removed:
level: 2;
54
Removed:
with: workoutLog prescription canonicalName.
55
Removed:
html form: [
56
Removed:
self renderWorkoutLogMetadataOn: html.
57
Removed:
setGroupLogComponents do: [ :each | html render: each ].
58
Removed:
self renderFormActionsOn: html ] ]
43
Added:
self
44
Added:
renderPageOn: html
45
Added:
with: [ html render: workoutLogEditorComponent ]
59
46
]
60
47
61
Removed:
{ #category : 'rendering' }
62
Removed:
MFTWorkoutLogEditorPage >> renderFormActionsOn: html [
63
Removed:
64
Removed:
html submitButton
65
Removed:
callback: [ self answer: workoutLog ];
66
Removed:
with: 'Save workout'.
67
Removed:
68
Removed:
html submitButton
69
Removed:
callback: [ self answer: nil ];
70
Removed:
with: 'Discard workout'
71
Removed:
]
72
Removed:
73
Removed:
{ #category : 'rendering' }
74
Removed:
MFTWorkoutLogEditorPage >> renderWorkoutLogMetadataOn: html [
75
Removed:
76
Removed:
^ html fieldSet with: [
77
Removed:
html div
78
Removed:
class: 'mft-form-items-container';
79
Removed:
with: [
80
Removed:
html label
81
Removed:
for: 'start-date';
82
Removed:
with: 'Start'.
83
Removed:
html span: [
84
Removed:
html dateInput5
85
Removed:
id: 'start-date';
86
Removed:
value: Date today yyyymmdd;
87
Removed:
callback: [ :value |
88
Removed:
workoutLog startDate:
89
Removed:
(Date readFrom: value pattern: 'yyyy-mm-dd') ].
90
Removed:
html timeInput5
91
Removed:
id: 'start-time';
92
Removed:
value: workoutLog start asTime print24;
93
Removed:
callback: [ :value |
94
Removed:
workoutLog startTime: (Time fromString: value) ] ] ].
95
Removed:
html div
96
Removed:
class: 'mft-form-items-container';
97
Removed:
with: [
98
Removed:
html label
99
Removed:
for: 'finish-date';
100
Removed:
with: 'Finish'.
101
Removed:
html span: [
102
Removed:
html dateInput5
103
Removed:
id: 'finish-date';
104
Removed:
value: Date today yyyymmdd;
105
Removed:
callback: [ :value |
106
Removed:
workoutLog finishDate:
107
Removed:
(Date readFrom: value pattern: 'yyyy-mm-dd') ].
108
Removed:
html timeInput5
109
Removed:
id: 'finish-time';
110
Removed:
callback: [ :value |
111
Removed:
value ifNotEmpty: [
112
Removed:
workoutLog finishTime: (Time fromString: value) ] ] ] ] ]
113
Removed:
]
114
Removed:
115
48
{ #category : 'accessing' }
116
49
MFTWorkoutLogEditorPage >> title [
117
50
@@ -121,8 +54,14 @@
121
54
{ #category : 'accessing' }
122
55
MFTWorkoutLogEditorPage >> workoutLog: aMFTWorkoutLog [
123
56
124
Removed:
workoutLog := aMFTWorkoutLog.
125
Removed:
setGroupLogComponents := workoutLog setGroups collect: [ :setGroupLog |
126
Removed:
MFTSetGroupLogViewerComponent forSetGroupLog:
127
Removed:
setGroupLog ]
57
Added:
workoutLog := aMFTWorkoutLog
58
Added:
]
59
Added:
60
Added:
{ #category : 'as yet unclassified' }
61
Added:
MFTWorkoutLogEditorPage >> workoutLogEditorComponent: aMFTWorkoutLogEditorComponent [
62
Added:
63
Added:
workoutLogEditorComponent := aMFTWorkoutLogEditorComponent
64
Added:
onSaveWorkout: [
65
Added:
self answer: workoutLog ];
66
Added:
onDiscardWorkout: [ self answer: nil ]
128
67
]
src/MyFitnessTracker-Web/MFTWorkoutLogViewerComponent.class.st
@@ -0,0 +1,89 @@
1
Added:
Class {
2
Added:
#name : 'MFTWorkoutLogViewerComponent',
3
Added:
#superclass : 'WAComponent',
4
Added:
#instVars : [
5
Added:
'heading',
6
Added:
'workoutLog',
7
Added:
'beEditable',
8
Added:
'setGroupLogComponents',
9
Added:
'onEdit'
10
Added:
],
11
Added:
#category : 'MyFitnessTracker-Web-Components',
12
Added:
#package : 'MyFitnessTracker-Web',
13
Added:
#tag : 'Components'
14
Added:
}
15
Added:
16
Added:
{ #category : 'as yet unclassified' }
17
Added:
MFTWorkoutLogViewerComponent class >> forWorkoutLog: aMFTWorkoutLog [
18
Added:
19
Added:
^ self new
20
Added:
workoutLog: aMFTWorkoutLog;
21
Added:
yourself
22
Added:
]
23
Added:
24
Added:
{ #category : 'accessing' }
25
Added:
MFTWorkoutLogViewerComponent >> heading: aString [
26
Added:
27
Added:
heading := aString
28
Added:
]
29
Added:
30
Added:
{ #category : 'initialization' }
31
Added:
MFTWorkoutLogViewerComponent >> initialize [
32
Added:
33
Added:
super initialize.
34
Added:
beEditable := false.
35
Added:
setGroupLogComponents := OrderedCollection new
36
Added:
]
37
Added:
38
Added:
{ #category : 'rendering' }
39
Added:
MFTWorkoutLogViewerComponent >> onEdit: aBlock [
40
Added:
41
Added:
onEdit := aBlock
42
Added:
]
43
Added:
44
Added:
{ #category : 'rendering' }
45
Added:
MFTWorkoutLogViewerComponent >> renderContentOn: html [
46
Added:
47
Added:
html section: [
48
Added:
html heading
49
Added:
level: 2;
50
Added:
with: heading.
51
Added:
html heading
52
Added:
level: 3;
53
Added:
with: workoutLog prescription canonicalName.
54
Added:
self renderWorkoutLogMetadataOn: html.
55
Added:
setGroupLogComponents do: [ :each | html render: each ].
56
Added:
self renderFormActionsOn: html ]
57
Added:
]
58
Added:
59
Added:
{ #category : 'rendering' }
60
Added:
MFTWorkoutLogViewerComponent >> renderFormActionsOn: html [
61
Added:
62
Added:
^ html form: [
63
Added:
html submitButton
64
Added:
callback: [ onEdit ];
65
Added:
with: 'Edit' ]
66
Added:
]
67
Added:
68
Added:
{ #category : 'rendering' }
69
Added:
MFTWorkoutLogViewerComponent >> renderWorkoutLogMetadataOn: html [
70
Added:
71
Added:
html definitionList: [
72
Added:
html
73
Added:
definitionTerm: 'Start time';
74
Added:
definitionData: workoutLog start asEmailString;
75
Added:
definitionTerm: 'Duration';
76
Added:
definitionData:
77
Added:
workoutLog duration asMinutes rounded asString , ' minutes';
78
Added:
definitionTerm: 'Intensity factor';
79
Added:
definitionData: workoutLog intensityFactor asString , '%' ]
80
Added:
]
81
Added:
82
Added:
{ #category : 'accessing' }
83
Added:
MFTWorkoutLogViewerComponent >> workoutLog: aMFTWorkoutLog [
84
Added:
85
Added:
workoutLog := aMFTWorkoutLog.
86
Added:
setGroupLogComponents := workoutLog setGroups collect: [ :setGroupLog |
87
Added:
MFTSetGroupLogViewerComponent
88
Added:
forSetGroupLog: setGroupLog ]
89
Added:
]
src/MyFitnessTracker-Web/MFTWorkoutPrescriptionViewerComponent.class.st
@@ -32,7 +32,7 @@
32
32
((setGroup sets collect: #exercise) joinUsing: ', ') ] ] ]
33
33
]
34
34
35
Removed:
{ #category : 'accessing' }
35
Added:
{ #category : 'as yet unclassified' }
36
36
MFTWorkoutPrescriptionViewerComponent >> workoutPrescription: aMFTWorkoutPrescription [
37
37
38
38
workoutPrescription := aMFTWorkoutPrescription