[Pharo] Personal fitness tracker web app.
Update view components.
Changed files
- src/MyFitnessTracker-Web/MFTExerciseSelectorComponent.class.st
- src/MyFitnessTracker-Web/MFTHomePage.class.st
- src/MyFitnessTracker-Web/MFTPlanEditorPage.class.st
- src/MyFitnessTracker-Web/MFTPlanPage.class.st
- src/MyFitnessTracker-Web/MFTRootComponent.class.st
- src/MyFitnessTracker-Web/MFTScreenComponent.class.st
- src/MyFitnessTracker-Web/MFTSetGroupLogEditorComponent.class.st
- src/MyFitnessTracker-Web/MFTWorkoutLogEditorComponent.class.st
- src/MyFitnessTracker-Web/MFTWorkoutPrescriptionTable.class.st
src/MyFitnessTracker-Web/MFTExerciseSelectorComponent.class.st
@@ -0,0 +1,50 @@
1
Added:
Class {
2
Added:
#name : 'MFTExerciseSelectorComponent',
3
Added:
#superclass : 'WAComponent',
4
Added:
#instVars : [
5
Added:
'exercises',
6
Added:
'selectedExercise'
7
Added:
],
8
Added:
#category : 'MyFitnessTracker-Web-Components',
9
Added:
#package : 'MyFitnessTracker-Web',
10
Added:
#tag : 'Components'
11
Added:
}
12
Added:
13
Added:
{ #category : 'as yet unclassified' }
14
Added:
MFTExerciseSelectorComponent class >> forExercises: aMFTExerciseCollection [
15
Added:
16
Added:
^ self new
17
Added:
exercises: aMFTExerciseCollection;
18
Added:
yourself
19
Added:
]
20
Added:
21
Added:
{ #category : 'accessing' }
22
Added:
MFTExerciseSelectorComponent >> exercises [
23
Added:
24
Added:
^ exercises
25
Added:
]
26
Added:
27
Added:
{ #category : 'accessing' }
28
Added:
MFTExerciseSelectorComponent >> exercises: aMFTExerciseCollection [
29
Added:
30
Added:
exercises := aMFTExerciseCollection
31
Added:
]
32
Added:
33
Added:
{ #category : 'rendering' }
34
Added:
MFTExerciseSelectorComponent >> renderContentOn: html [
35
Added:
36
Added:
html form: [
37
Added:
html select
38
Added:
list: exercises;
39
Added:
selected: selectedExercise;
40
Added:
callback: [ :value | selectedExercise := value ].
41
Added:
html submitButton
42
Added:
callback: [ self answer: selectedExercise ];
43
Added:
with: 'Submit' ]
44
Added:
]
45
Added:
46
Added:
{ #category : 'accessing' }
47
Added:
MFTExerciseSelectorComponent >> selectedExercise: aMFTExercise [
48
Added:
49
Added:
selectedExercise := aMFTExercise
50
Added:
]
src/MyFitnessTracker-Web/MFTHomePage.class.st
@@ -15,14 +15,6 @@
15
15
onLogWorkout := aBlock
16
16
]
17
17
18
Removed:
{ #category : 'initialization' }
19
Removed:
MFTHomePage >> previousWorkoutLogsComponent [
20
Removed:
21
Removed:
^ MFTLogBookViewerComponent new
22
Removed:
logBook: self session user trainee logBook;
23
Removed:
heading: 'Previous workouts'
24
Removed:
]
25
Removed:
26
18
{ #category : 'rendering' }
27
19
MFTHomePage >> renderContentOn: html [
28
20
@@ -30,19 +22,18 @@
30
22
html heading
31
23
level: 1;
32
24
with: self session user trainee routine canonicalName capitalized.
33
Removed:
self renderStatusOn: html.
34
Removed:
html horizontalRule.
35
25
self
26
Added:
renderStatusOn: html;
36
27
renderNextWorkoutPrescriptionOn: html;
37
28
renderMainActionsOn: html.
38
Removed:
html horizontalRule.
39
Removed:
self renderWorkoutLogBookOn: html ]
29
Added:
self session user trainee logBook workoutLogs ifNotEmpty: [
30
Added:
self renderWorkoutLogBookOn: html ] ]
40
31
]
41
32
42
33
{ #category : 'rendering' }
43
34
MFTHomePage >> renderMainActionsOn: html [
44
35
45
Removed:
html section: [
36
Added:
html div: [
46
37
html anchor
47
38
callback: [ onLogWorkout value ];
48
39
with: 'Log workout' ]
@@ -55,17 +46,14 @@
55
46
workoutPrescription := self session user trainee
56
47
nextWorkoutPrescription.
57
48
58
Removed:
html section: [
59
Removed:
html heading
60
Removed:
level: 2;
61
Removed:
with: 'Next workout'.
62
Removed:
html heading
63
Removed:
level: 3;
64
Removed:
with: workoutPrescription canonicalName.
65
Removed:
html orderedList: [
66
Removed:
workoutPrescription setGroups do: [ :setGroup |
67
Removed:
html listItem:
68
Removed:
((setGroup sets collect: #exercise) joinUsing: ', ') ] ] ]
49
Added:
html heading
50
Added:
level: 2;
51
Added:
with: 'Next workout'.
52
Added:
html heading
53
Added:
level: 3;
54
Added:
with: workoutPrescription canonicalName.
55
Added:
html render:
56
Added:
(MFTWorkoutPrescriptionTable forPrescription: workoutPrescription)
69
57
]
70
58
71
59
{ #category : 'rendering' }
@@ -74,29 +62,45 @@
74
62
| trainee |
75
63
trainee := self session user trainee.
76
64
77
Removed:
html section: [
78
Removed:
html definitionList: [
79
Removed:
trainee logBook durationSinceLastWorkout ifNotNil: [
80
Removed:
html definitionTerm: 'Hours since last workout'.
81
Removed:
html definitionData:
65
Added:
html definitionList: [
66
Added:
trainee logBook durationSinceLastWorkout ifNotNil: [
67
Added:
html
68
Added:
definitionTerm: 'Hours since last workout';
69
Added:
definitionData:
82
70
trainee logBook durationSinceLastWorkout asHours rounded asString ].
83
Removed:
html definitionTerm: 'Recovery status'.
84
Removed:
html definitionData: (trainee isRecovered
71
Added:
html
72
Added:
definitionTerm: 'Recovery status';
73
Added:
definitionData: (trainee isRecovered
85
74
ifTrue: [ 'Fully recovered' ]
86
Removed:
ifFalse: [ 'Not recovered yet' ]) ] ]
75
Added:
ifFalse: [ 'Not recovered yet' ]) ]
87
76
]
88
77
89
78
{ #category : 'rendering' }
90
79
MFTHomePage >> renderWorkoutLogBookOn: html [
91
80
92
Removed:
| logBook |
93
Removed:
logBook := self session user trainee logBook.
94
Removed:
95
Removed:
logBook workoutLogs ifNotEmpty: [
96
Removed:
html heading
97
Removed:
level: 2;
98
Removed:
with: 'Previous workouts'.
99
Removed:
logBook workoutLogs reverseDo: [ :each | html render: each ] ]
81
Added:
html heading
82
Added:
level: 2;
83
Added:
with: 'Previous workouts'.
84
Added:
html table
85
Added:
style: 'max-width: 30rem';
86
Added:
with: [
87
Added:
html
88
Added:
tableHead: [
89
Added:
html tableRow: [
90
Added:
html
91
Added:
tableData: 'Date';
92
Added:
tableData: 'Name';
93
Added:
tableData: 'Volume';
94
Added:
tableData: 'Intensity' ] ];
95
Added:
tableBody: [
96
Added:
self session user trainee logBook workoutLogs reverseDo: [
97
Added:
:workoutLog |
98
Added:
html tableRow: [
99
Added:
html
100
Added:
tableData: workoutLog start asDate yyyymmdd;
101
Added:
tableData: workoutLog canonicalName;
102
Added:
tableData: workoutLog volume;
103
Added:
tableData: workoutLog intensityFactor asString , '%' ] ] ] ]
100
104
]
101
105
102
106
{ #category : 'accessing' }
src/MyFitnessTracker-Web/MFTPlanEditorPage.class.st
@@ -0,0 +1,53 @@
1
Added:
Class {
2
Added:
#name : 'MFTPlanEditorPage',
3
Added:
#superclass : 'MFTPage',
4
Added:
#instVars : [
5
Added:
'routine'
6
Added:
],
7
Added:
#category : 'MyFitnessTracker-Web-Components',
8
Added:
#package : 'MyFitnessTracker-Web',
9
Added:
#tag : 'Components'
10
Added:
}
11
Added:
12
Added:
{ #category : 'as yet unclassified' }
13
Added:
MFTPlanEditorPage class >> forRoutine: aMFTRoutine [
14
Added:
15
Added:
^ self new
16
Added:
routine: aMFTRoutine;
17
Added:
yourself
18
Added:
]
19
Added:
20
Added:
{ #category : 'rendering' }
21
Added:
MFTPlanEditorPage >> renderContentOn: html [
22
Added:
23
Added:
self renderPageOn: html with: [
24
Added:
html heading
25
Added:
level: 1;
26
Added:
with: 'Edit plan'.
27
Added:
html heading
28
Added:
level: 2;
29
Added:
with: routine canonicalName.
30
Added:
html form: [
31
Added:
html div
32
Added:
class: 'grid';
33
Added:
with: [
34
Added:
html button
35
Added:
callback: [ self answer: routine ];
36
Added:
with: 'Save plan'.
37
Added:
html button
38
Added:
class: 'secondary';
39
Added:
callback: [ self answer ];
40
Added:
with: 'Cancel' ] ] ]
41
Added:
]
42
Added:
43
Added:
{ #category : 'accessing' }
44
Added:
MFTPlanEditorPage >> routine: aMFTRoutine [
45
Added:
46
Added:
routine := aMFTRoutine
47
Added:
]
48
Added:
49
Added:
{ #category : 'accessing' }
50
Added:
MFTPlanEditorPage >> title [
51
Added:
52
Added:
^ 'Edit plan'
53
Added:
]
src/MyFitnessTracker-Web/MFTPlanPage.class.st
@@ -1,18 +1,28 @@
1
1
Class {
2
2
#name : 'MFTPlanPage',
3
3
#superclass : 'MFTPage',
4
Added:
#instVars : [
5
Added:
'onChangePlan'
6
Added:
],
4
7
#category : 'MyFitnessTracker-Web-Components',
5
8
#package : 'MyFitnessTracker-Web',
6
9
#tag : 'Components'
7
10
}
8
11
9
12
{ #category : 'rendering' }
13
Added:
MFTPlanPage >> onChangePlan: aBlock [
14
Added:
15
Added:
onChangePlan := aBlock
16
Added:
]
17
Added:
18
Added:
{ #category : 'rendering' }
10
19
MFTPlanPage >> renderContentOn: html [
11
20
12
21
self renderPageOn: html with: [
13
Removed:
html heading: 'Plan'.
22
Added:
html heading: 'Current plan'.
14
23
self
15
24
renderCurrentPlanInfoOn: html;
25
Added:
renderPlanActionsOn: html;
16
26
renderPlanWorkoutsOn: html ]
17
27
]
18
28
@@ -22,17 +32,25 @@
22
32
| routine |
23
33
routine := self session user trainee routine.
24
34
25
Removed:
html section: [
26
Removed:
html definitionList: [
27
Removed:
html
28
Removed:
definitionTerm: 'Current routine';
29
Removed:
definitionData: routine canonicalName.
30
Removed:
html
31
Removed:
definitionTerm: 'Rest between workouts';
32
Removed:
definitionData: '48 hours' ] ]
35
Added:
html definitionList: [
36
Added:
html
37
Added:
definitionTerm: 'Current routine';
38
Added:
definitionData: routine canonicalName.
39
Added:
html
40
Added:
definitionTerm: 'Rest between workouts';
41
Added:
definitionData: '48 hours' ]
33
42
]
34
43
35
44
{ #category : 'rendering' }
45
Added:
MFTPlanPage >> renderPlanActionsOn: html [
46
Added:
47
Added:
html div: [
48
Added:
html anchor
49
Added:
callback: [ onChangePlan value ];
50
Added:
with: 'Change plan' ]
51
Added:
]
52
Added:
53
Added:
{ #category : 'rendering' }
36
54
MFTPlanPage >> renderPlanWorkoutsOn: html [
37
55
38
56
| routine |
@@ -41,16 +59,9 @@
41
59
routine workouts do: [ :workoutPrescription |
42
60
html heading
43
61
level: 2;
44
Removed:
with: workoutPrescription canonicalName.
45
Removed:
html orderedList: [
46
Removed:
workoutPrescription setGroups do: [ :setGroup |
47
Removed:
html listItem: [
48
Removed:
html
49
Removed:
text: setGroup canonicalName capitalized;
50
Removed:
text: ': ';
51
Removed:
text:
52
Removed:
((setGroup sets collect: [ :set | set exercise canonicalName ])
53
Removed:
joinUsing: ', ') ] ] ] ]
62
Added:
with: workoutPrescription canonicalName capitalized.
63
Added:
html render:
64
Added:
(MFTWorkoutPrescriptionTable forPrescription: workoutPrescription) ]
54
65
]
55
66
56
67
{ #category : 'accessing' }
src/MyFitnessTracker-Web/MFTRootComponent.class.st
@@ -57,5 +57,6 @@
57
57
url: MFTFileLibrary / #faviconPng.
58
58
aRoot stylesheet url:
59
59
'https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css'.
60
Removed:
aRoot stylesheet url: MFTFileLibrary / #defaultCss
60
Added:
aRoot stylesheet url: MFTFileLibrary / #defaultCss.
61
Added:
aRoot stylesheet url: 'https://rsms.me/inter/inter.css'
61
62
]
src/MyFitnessTracker-Web/MFTScreenComponent.class.st
@@ -56,13 +56,21 @@
56
56
{ #category : 'initialization' }
57
57
MFTScreenComponent >> initializeMainPages [
58
58
59
Added:
| trainee |
60
Added:
trainee := self session user trainee.
61
Added:
59
62
mainPages := OrderedDictionary newFrom: {
60
63
(#home -> (MFTHomePage new onLogWorkout: [
64
Added:
| workoutLog |
65
Added:
workoutLog := activePage call:
66
Added:
(MFTWorkoutLogEditorPage
67
Added:
forWorkoutPrescription:
68
Added:
trainee nextWorkoutPrescription).
69
Added:
workoutLog ifNotNil: [
70
Added:
trainee logWorkout: workoutLog ] ])).
71
Added:
(#plan -> (MFTPlanPage new onChangePlan: [
61
72
activePage call:
62
Removed:
(MFTWorkoutLogEditorPage forWorkoutPrescription:
63
Removed:
self session user trainee
64
Removed:
nextWorkoutPrescription) ])).
65
Removed:
(#plan -> MFTPlanPage new).
73
Added:
(MFTPlanEditorPage forRoutine: trainee routine) ])).
66
74
(#profile -> MFTProfilePage new) }
67
75
]
68
76
src/MyFitnessTracker-Web/MFTSetGroupLogEditorComponent.class.st
@@ -37,12 +37,13 @@
37
37
with: [
38
38
html button
39
39
callback: [ self answer: setGroupLog ];
40
Removed:
with: 'Save'
41
Removed:
42
Removed:
"html button
40
Added:
with: 'Save'.
41
Added:
html button
43
42
class: 'secondary';
44
Removed:
callback: [ self answer: nil ];
45
Removed:
with: 'Discard'" ]
43
Added:
callback: [
44
Added:
setGroupLog := MFTSetGroupLog forPrescription:
45
Added:
setGroupLog prescription ];
46
Added:
with: 'Reset' ]
46
47
]
47
48
48
49
{ #category : 'rendering' }
@@ -52,54 +53,64 @@
52
53
html heading
53
54
level: 4;
54
55
with: exercise canonicalName capitalized.
55
Removed:
html button
56
Removed:
class: 'secondary outline';
57
Removed:
callback: [
58
Removed:
setGroupLog
59
Removed:
addSet: (MFTSetLog forPrescription: sets last prescription)
60
Removed:
before: sets first ];
61
Removed:
with: 'Add warm-up set'.
56
Added:
html div
57
Added:
class: 'grid';
58
Added:
with: [
59
Added:
html button
60
Added:
class: 'outline';
61
Added:
callback: [
62
Added:
setGroupLog
63
Added:
addSet: (MFTSetLog forPrescription: sets last prescription)
64
Added:
before: sets first ];
65
Added:
with: 'Add set'.
66
Added:
html button
67
Added:
class: 'outline secondary';
68
Added:
callback: [
69
Added:
| alternativeExercises selectedExercise |
70
Added:
alternativeExercises := setGroupLog prescription
71
Added:
alternativeExercisesFor: exercise.
72
Added:
selectedExercise := self call:
73
Added:
((MFTExerciseSelectorComponent
74
Added:
forExercises: alternativeExercises)
75
Added:
selectedExercise: exercise).
76
Added:
selectedExercise ifNotNil: [ "TODO" setGroupLog ] ];
77
Added:
with: 'Substitute exercise' ].
62
78
self renderTableOn: html forSets: sets ]
63
79
]
64
80
65
81
{ #category : 'rendering' }
66
82
MFTSetGroupLogEditorComponent >> renderTableOn: html forSets: sets [
67
83
68
Removed:
^ html table: [
69
Removed:
html
70
Removed:
tableHead: [
71
Removed:
html tableRow: [
72
Removed:
html
73
Removed:
tableHeading;
74
Removed:
tableHeading: 'Reps';
75
Removed:
tableHeading: 'Load';
76
Removed:
tableHeading: 'To Failure';
77
Removed:
tableHeading ] ];
78
Removed:
tableBody: [
79
Removed:
sets do: [ :setLog |
80
Removed:
html tableRow: [
81
Removed:
html
82
Removed:
tableData: (setGroupLog indexOfSet: setLog);
83
Removed:
tableData: [
84
Removed:
html numberInput
85
Removed:
placeholder: setLog prescription repScheme;
86
Removed:
callback: [ :value |
87
Removed:
value ifNotEmpty: [ setLog reps: value asNumber ] ];
88
Removed:
value: setLog reps ];
89
Removed:
tableData: [
90
Removed:
html numberInput
91
Removed:
callback: [ :value |
92
Removed:
value ifNotEmpty: [ setLog load: value asNumber ] ];
93
Removed:
value: setLog load ];
94
Removed:
tableData: [
95
Removed:
html checkbox
96
Removed:
callback: [ :value | setLog failureAchieved: value ];
97
Removed:
value: setLog failureAchieved ];
98
Removed:
tableData: [
99
Removed:
html button
100
Removed:
class: 'outline';
101
Removed:
callback: [ setGroupLog removeSet: setLog ];
102
Removed:
with: 'Delete' ] ] ] ] ]
84
Added:
html table: [
85
Added:
html
86
Added:
tableHead: [
87
Added:
html tableRow: [
88
Added:
html
89
Added:
tableHeading;
90
Added:
tableHeading: 'Reps';
91
Added:
tableHeading: 'Load';
92
Added:
tableHeading: 'Failure' ] ];
93
Added:
tableBody: [
94
Added:
sets doWithIndex: [ :setLog :setLogIdx |
95
Added:
html tableRow: [
96
Added:
html
97
Added:
tableData: setLogIdx;
98
Added:
tableData: [
99
Added:
html numberInput
100
Added:
placeholder: setLog prescription repScheme;
101
Added:
callback: [ :value |
102
Added:
value ifNotEmpty: [ setLog reps: value asNumber ] ];
103
Added:
value: setLog reps ];
104
Added:
tableData: [
105
Added:
html numberInput
106
Added:
callback: [ :value |
107
Added:
value ifNotEmpty: [ setLog load: value asNumber ] ];
108
Added:
value: setLog load ];
109
Added:
tableData: [
110
Added:
html button
111
Added:
class: 'outline';
112
Added:
callback: [ ];
113
Added:
value: setLog failureAchieved ] ] ] ] ]
103
114
]
104
115
105
116
{ #category : 'accessing' }
src/MyFitnessTracker-Web/MFTWorkoutLogEditorComponent.class.st
@@ -95,17 +95,20 @@
95
95
| isCompletelyLogged |
96
96
isCompletelyLogged := setGroupLog isCompletelyLogged.
97
97
98
Removed:
html section: [
99
Removed:
html heading
100
Removed:
level: 3;
101
Removed:
with: setGroupLog canonicalName capitalized.
102
Removed:
html heading
103
Removed:
level: 4;
104
Removed:
with:
105
Removed:
(setGroupLog uniqueExercisesInSets asOrderedCollection
106
Removed:
joinUsing: ', ').
107
Removed:
98
Added:
html heading
99
Added:
level: 3;
100
Added:
with: setGroupLog canonicalName capitalized.
101
Added:
html heading
102
Added:
level: 4;
103
Added:
with:
104
Added:
(setGroupLog uniqueExercisesInSets asOrderedCollection joinUsing:
105
Added:
', ').
106
Added:
html paragraph: [
108
107
isCompletelyLogged ifTrue: [
108
Added:
html definitionList: [
109
Added:
html
110
Added:
definitionTerm: 'Intensity factor';
111
Added:
definitionData: setGroupLog intensityFactor ].
109
112
self renderSetGroupLogData: setGroupLog on: html ].
110
113
html anchor
111
114
callback: [
src/MyFitnessTracker-Web/MFTWorkoutPrescriptionTable.class.st
@@ -0,0 +1,50 @@
1
Added:
Class {
2
Added:
#name : 'MFTWorkoutPrescriptionTable',
3
Added:
#superclass : 'WAComponent',
4
Added:
#instVars : [
5
Added:
'workoutPrescription'
6
Added:
],
7
Added:
#category : 'MyFitnessTracker-Web-Components',
8
Added:
#package : 'MyFitnessTracker-Web',
9
Added:
#tag : 'Components'
10
Added:
}
11
Added:
12
Added:
{ #category : 'accessing' }
13
Added:
MFTWorkoutPrescriptionTable class >> forPrescription: aMFTWorkoutPrescription [
14
Added:
15
Added:
^ self new
16
Added:
workoutPrescription: aMFTWorkoutPrescription;
17
Added:
yourself
18
Added:
]
19
Added:
20
Added:
{ #category : 'rendering' }
21
Added:
MFTWorkoutPrescriptionTable >> renderContentOn: html [
22
Added:
23
Added:
html table
24
Added:
style: 'max-width: 30rem';
25
Added:
with: [
26
Added:
html
27
Added:
tableHead: [
28
Added:
html
29
Added:
tableHeading;
30
Added:
tableHeading: 'Set';
31
Added:
tableHeading: 'Exercise' ];
32
Added:
tableBody: [
33
Added:
workoutPrescription setGroups doWithIndex: [ :setGroup :setGroupIdx |
34
Added:
html tableRow: [
35
Added:
html tableData
36
Added:
attributeAt: 'rowspan' put: setGroup sets size + 1;
37
Added:
with: setGroupIdx.
38
Added:
html tableData
39
Added:
attributeAt: 'rowspan' put: setGroup sets size + 1;
40
Added:
with: setGroup canonicalName capitalized ].
41
Added:
setGroup uniqueExercisesInSets do: [ :exercise |
42
Added:
html tableRow: [
43
Added:
html tableData: exercise canonicalName capitalized ] ] ] ] ]
44
Added:
]
45
Added:
46
Added:
{ #category : 'accessing' }
47
Added:
MFTWorkoutPrescriptionTable >> workoutPrescription: aMFTWorkoutPrescription [
48
Added:
49
Added:
workoutPrescription := aMFTWorkoutPrescription
50
Added:
]