mumuki-laboratory 8.0.0 → 8.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/mumuki_laboratory/application/gamification.js +89 -11
  3. data/app/assets/javascripts/mumuki_laboratory/application/kids.js +16 -4
  4. data/app/assets/javascripts/mumuki_laboratory/application/kindergarten.js +9 -50
  5. data/app/assets/javascripts/mumuki_laboratory/application/mu-modal-carrousel.js +63 -0
  6. data/app/assets/javascripts/mumuki_laboratory/application/number-counter.js +18 -0
  7. data/app/assets/javascripts/mumuki_laboratory/application/primary.js +2 -1
  8. data/app/assets/javascripts/mumuki_laboratory/application/submission.js +1 -1
  9. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_kids_results.scss +117 -0
  10. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_kindergarten.scss +45 -131
  11. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_terms.scss +9 -12
  12. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_user_profile.scss +31 -3
  13. data/app/controllers/application_controller.rb +40 -8
  14. data/app/controllers/assets_controller.rb +1 -0
  15. data/app/controllers/book_discussions_controller.rb +1 -1
  16. data/app/controllers/chapters_controller.rb +1 -0
  17. data/app/controllers/discussions_controller.rb +4 -0
  18. data/app/controllers/exercises_controller.rb +1 -0
  19. data/app/controllers/guides_controller.rb +2 -0
  20. data/app/controllers/invitations_controller.rb +1 -0
  21. data/app/controllers/lessons_controller.rb +1 -0
  22. data/app/controllers/login_controller.rb +1 -0
  23. data/app/controllers/users_controller.rb +8 -1
  24. data/app/helpers/assistance_box_helper.rb +7 -5
  25. data/app/helpers/gamification_helper.rb +5 -0
  26. data/app/helpers/links_helper.rb +1 -1
  27. data/app/views/exercise_solutions/_assistant_rules_box.html.erb +13 -0
  28. data/app/views/exercise_solutions/_contextualization_results_container.html.erb +9 -0
  29. data/app/views/exercise_solutions/_kids_level_up.html.erb +11 -0
  30. data/app/views/exercise_solutions/_results.html.erb +19 -19
  31. data/app/views/exercise_solutions/_results_title.html.erb +5 -0
  32. data/app/views/exercises/show.html.erb +4 -1
  33. data/app/views/layouts/_kindergarten.html.erb +1 -1
  34. data/app/views/layouts/_organizations_listing.html.erb +8 -12
  35. data/app/views/layouts/application.html.erb +8 -2
  36. data/app/views/layouts/modals/_guide_corollary.html.erb +1 -1
  37. data/app/views/layouts/modals/_kids_context.html.erb +1 -1
  38. data/app/views/layouts/modals/_kids_results.html.erb +16 -6
  39. data/app/views/layouts/modals/_kindergarten_context.html.erb +15 -15
  40. data/app/views/layouts/modals/_kindergarten_results.html.erb +20 -7
  41. data/app/views/layouts/modals/_kindergarten_results_aborted.html.erb +4 -4
  42. data/app/views/layouts/modals/_level_up.html.erb +27 -0
  43. data/app/views/users/_edit_user_form.html.erb +1 -1
  44. data/app/views/users/_user_form.html.erb +12 -2
  45. data/app/views/users/terms.html.erb +12 -0
  46. data/config/routes.rb +8 -8
  47. data/lib/mumuki/laboratory.rb +18 -5
  48. data/lib/mumuki/laboratory/controllers.rb +2 -0
  49. data/lib/mumuki/laboratory/controllers/action_redirector.rb +21 -0
  50. data/lib/mumuki/laboratory/controllers/immersive_navigation.rb +7 -0
  51. data/lib/mumuki/laboratory/controllers/results_rendering.rb +1 -0
  52. data/lib/mumuki/laboratory/events/events.rb +0 -9
  53. data/lib/mumuki/laboratory/locales/en.yml +5 -0
  54. data/lib/mumuki/laboratory/locales/es-CL.yml +5 -0
  55. data/lib/mumuki/laboratory/locales/es.yml +5 -0
  56. data/lib/mumuki/laboratory/locales/pt.yml +5 -0
  57. data/lib/mumuki/laboratory/version.rb +1 -1
  58. data/spec/capybara_helper.rb +5 -1
  59. data/spec/controllers/exercise_solutions_controller_spec.rb +1 -1
  60. data/spec/features/immersive_redirection_spec.rb +181 -0
  61. data/spec/features/profile_flow_spec.rb +35 -3
  62. data/spec/features/terms_flow_spec.rb +151 -0
  63. metadata +110 -101
  64. data/app/helpers/organization_list_helper.rb +0 -5
  65. data/spec/features/choose_organization_spec.rb +0 -74
@@ -87,155 +87,69 @@ $modal-footer-height: 95px;
87
87
  }
88
88
  }
89
89
 
90
- .mu-kindergarten-context {
90
+ .modal-content.kindergarten {
91
+ $width-lg: 800px;
92
+ $height-lg: $width-lg * 0.625;
91
93
 
92
- .modal-dialog {
94
+ width: $width-lg;
95
+ height: $height-lg;
93
96
 
94
- height: 100vh;
95
- width: 100vw;
96
- margin: 0;
97
+ top: calc(50vh - #{$height-lg} / 2);
97
98
 
98
- .modal-content {
99
- position: absolute;
100
-
101
- $width-lg: 800px;
102
- $height-lg: $width-lg * 0.625;
103
-
104
- width: $width-lg;
105
- height: $height-lg;
106
-
107
- top: calc(50vh - #{$height-lg} / 2);
108
- left: calc(50vw - #{$width-lg} / 2);
109
-
110
- @media (orientation: landscape) and (max-height: $height-lg + 50px) {
111
- $height-sm: 85vh;
112
- $width-sm: $height-sm / 0.625;
99
+ @media (orientation: landscape) and (max-height: $height-lg + 50px) {
100
+ $height-sm: 85vh;
101
+ $width-sm: $height-sm / 0.625;
113
102
 
114
- width: $width-sm;
115
- height: $height-sm;
103
+ width: $width-sm;
104
+ height: $height-sm;
116
105
 
117
- top: calc(50vh - #{$height-sm} / 2);
118
- left: calc(50vw - #{$width-sm} / 2);
119
- }
120
-
121
- @media (orientation: portrait) {
122
- $height-sm: 85vh;
123
- $width-sm: 85vw;
124
-
125
- width: $width-sm;
126
- height: $height-sm;
127
-
128
- top: calc(50vh - #{$height-sm} / 2);
129
- left: calc(50vw - #{$width-sm} / 2);
130
- }
106
+ top: calc(50vh - #{$height-sm} / 2);
107
+ left: calc(50vw - #{$width-sm} / 2);
108
+ }
131
109
 
132
- $border-width: 16px;
133
- border-width: $border-width;
134
- border-style: solid;
135
- border-color: $mu-color-link;
136
- border-radius: $border-width;
137
- box-shadow: none;
110
+ @media (orientation: portrait) {
111
+ $height-sm: 85vh;
112
+ $width-sm: 85vw;
138
113
 
139
- .modal-header,
140
- .modal-footer {
141
- text-align: center;
142
- text-transform: uppercase;
143
- }
114
+ width: $width-sm;
115
+ height: $height-sm;
144
116
 
145
- .modal-body {
146
- height: 100%;
147
- div, p {
148
- height: 100%;
149
- .mu-kindergarten-context-image-slides {
150
- img:not(.active) {
151
- display: none;
152
- }
153
- }
154
- img {
155
- width: 100%;
156
- height: 100%;
157
- object-position: center;
158
- object-fit: contain;
159
- }
160
- }
161
- }
117
+ top: calc(50vh - #{$height-sm} / 2);
118
+ left: calc(50vw - #{$width-sm} / 2);
119
+ }
162
120
 
163
- .mu-kindergarten-modal-button {
164
- $diameter: 64px;
165
- position: absolute;
166
- border-radius: 50%;
167
- height: $diameter;
168
- width: $diameter;
169
- color: white;
170
- font-weight: bold;
171
- border: none;
172
- padding: 0;
173
- background: $mu-color-link;
174
- &.mu-next,
175
- &.mu-close {
176
- top: - $diameter / 2 - $border-width / 2;
177
- right: - $diameter / 2 - $border-width / 2;
178
- }
179
- &.mu-previous {
180
- top: - $diameter / 2 - $border-width / 2;
181
- left: - $diameter / 2 - $border-width / 2;
182
- }
183
- }
121
+ .modal-header,
122
+ .modal-footer {
123
+ text-align: center;
124
+ text-transform: uppercase;
125
+ }
184
126
 
185
- $mu-statuses-colors: (
186
- 'broken': $mu-color-broken,
187
- 'danger': $mu-color-danger,
188
- 'success': $mu-color-success,
189
- 'warning': $mu-color-warning,
190
- 'passed': $mu-color-success,
191
- 'passed-with-warnings': $mu-color-warning,
192
- 'failed': $mu-color-danger,
193
- 'errored': $mu-color-broken,
194
- 'aborted': $mu-color-broken,
195
- 'pending': $mu-color-info
196
- );
197
-
198
- @each $class, $color in $mu-statuses-colors {
199
- &.#{$class} {
200
- border-color: $color;
201
- .mu-kindergarten-modal-button {
202
- background: $color;
203
- }
204
- }
205
- .submission-results {
206
- width: 100%;
207
- height: 100%;
208
- .mu-kids-callout-#{$class},
209
- p {
210
- display: none;
211
- }
212
- .mu-kids-default-#{$class} {
213
- width: 100%;
214
- height: 100%;
215
- img {
216
- width: 100%;
217
- height: 100%;
218
- object-position: center;
219
- object-fit: contain;
220
- }
221
- }
222
- }
223
- }
127
+ .modal-body.mu-kids-context-body {
128
+ height: 100%;
129
+ div img, p img {
130
+ width: 100%;
131
+ height: 100%;
132
+ object-position: center;
133
+ object-fit: contain;
224
134
  }
225
135
  }
226
136
  }
227
137
 
228
- #kids-results.mu-kindergarten-context {
138
+ #kids-results.mu-kids-modal-border {
229
139
  .modal-body{
230
140
  height: calc(100% - #{$modal-header-height} - #{$modal-footer-height});
231
141
  }
232
142
  }
233
- #kids-results-aborted.mu-kindergarten-context {
234
- .modal-body{
235
- height: calc(100% - #{$modal-header-height});
236
- }
237
- h4.modal-header {
238
- margin: 0;
143
+
144
+ #kids-results-aborted.mu-kids-modal-border {
145
+ .modal-content.kindergarten {
146
+ .modal-body {
147
+ height: calc(100% - #{$modal-header-height});
148
+ }
149
+
150
+ h4.modal-header {
151
+ margin: 0;
152
+ }
239
153
  }
240
154
  }
241
155
 
@@ -1,12 +1,3 @@
1
- summary.terms-summary {
2
- font-size: 29px;
3
- outline: 0;
4
- cursor: pointer;
5
- .terms-summary-title {
6
- display: inline;
7
- }
8
- }
9
-
10
1
  .terms-card {
11
2
  position: relative;
12
3
  display: -ms-flexbox;
@@ -38,7 +29,13 @@ summary.terms-summary {
38
29
  padding: 1.25rem;
39
30
  }
40
31
 
41
- .terms-acceptance-btn {
42
- margin-top: 10px;
43
- display: block
32
+ .terms-acceptance {
33
+ margin-top: 30px;
34
+
35
+ .terms-acceptance-btn {
36
+ margin-top: 10px;
37
+ display: block
38
+ }
44
39
  }
40
+
41
+
@@ -31,7 +31,37 @@
31
31
  }
32
32
  }
33
33
 
34
- .mu-profile-info {
34
+ .mu-profile-info-left {
35
+ display: flex;
36
+ flex-direction: column;
37
+ align-items: center;
38
+ text-align: center;
39
+
40
+ .mu-level-progress {
41
+ position: relative;
42
+ top: -275px;
43
+ margin-bottom: -275px;
44
+ }
45
+ }
46
+
47
+ .mu-level {
48
+ .mu-level-number {
49
+ position: absolute;
50
+ margin-top: 11px;
51
+ margin-left: -86px;
52
+ width: 87px;
53
+
54
+ text-align: center;
55
+ font-size: 1.5em;
56
+ font-weight: bold;
57
+ color: white;
58
+
59
+ user-select: none;
60
+ pointer-events: none;
61
+ }
62
+ }
63
+
64
+ .mu-profile-info-right {
35
65
  font-size: 20px;
36
66
  margin-top: 5px;
37
67
  div {
@@ -40,6 +70,4 @@
40
70
  font-style: italic;
41
71
  }
42
72
  }
43
-
44
-
45
73
  }
@@ -12,6 +12,7 @@ class ApplicationController < ActionController::Base
12
12
  include Mumuki::Laboratory::Controllers::DynamicErrors
13
13
  include Mumuki::Laboratory::Controllers::EmbeddedMode
14
14
  include Mumuki::Laboratory::Controllers::IncognitoMode
15
+ include Mumuki::Laboratory::Controllers::ActionRedirector
15
16
 
16
17
  before_action :set_current_organization!
17
18
  before_action :set_locale!
@@ -24,6 +25,7 @@ class ApplicationController < ActionController::Base
24
25
  before_action :authorize_if_private!
25
26
  before_action :validate_active_organization!
26
27
  before_action :validate_user_profile!, if: :current_user?
28
+ before_action :validate_accepted_role_terms!, if: :current_user?
27
29
 
28
30
  before_action :visit_organization!, if: :current_user?
29
31
 
@@ -36,23 +38,26 @@ class ApplicationController < ActionController::Base
36
38
  :has_notifications?,
37
39
  :subject,
38
40
  :should_choose_organization?,
41
+ :current_immersive_organizations,
39
42
  :theme_stylesheet_url,
40
- :extension_javascript_url
43
+ :extension_javascript_url,
44
+ :current_immersive_path
41
45
 
42
46
  def immersive_context_wrong?
43
47
  current_immersive_context != Organization.current
44
48
  end
45
49
 
46
50
  def redirect_to_proper_context!
47
- # TODO: redirect to subject (if it exists on the immersive context)
48
- redirect_to current_immersive_context.url_for('/')
51
+ redirect_to current_immersive_path_for(*current_immersive_context_and_content)
49
52
  end
50
53
 
51
54
  def should_choose_organization?
52
55
  return false unless current_user?
56
+ current_immersive_organizations.multiple?
57
+ end
53
58
 
54
- # TODO: replace `nil` with `subject` to consider exercise, guide, etc
55
- current_user.immersive_organizations_at(nil).size > 1
59
+ def current_immersive_organizations
60
+ current_user.immersive_organizations_with_content_at(subject)
56
61
  end
57
62
 
58
63
  # ensures contents are accessible to current user
@@ -66,7 +71,6 @@ class ApplicationController < ActionController::Base
66
71
  Organization.current.validate_active!
67
72
  end
68
73
 
69
-
70
74
  # required by Mumukit::Login
71
75
  def login_button(options = {})
72
76
  login_form.button_html I18n.t(:sign_in), options[:class]
@@ -82,11 +86,31 @@ class ApplicationController < ActionController::Base
82
86
  Mumuki::Domain::Workspace.new(current_user, Organization.current)
83
87
  end
84
88
 
89
+ def current_immersive_path(context)
90
+ current_immersive_path_for context, subject&.navigable_content_in(context)
91
+ end
92
+
93
+ def current_immersive_path_for(context, content)
94
+ resource = content ? polymorphic_path(content) : default_immersive_path_for(context)
95
+ context.url_for resource
96
+ end
97
+
85
98
  private
86
99
 
100
+ def default_immersive_path_for(context)
101
+ subject.present? ? root_path : inorganic_path_for(request)
102
+ end
103
+
104
+ def inorganic_path_for(request)
105
+ Mumukit::Platform.organization_mapping.inorganic_path_for(request)
106
+ end
107
+
87
108
  def current_immersive_context
88
- # TODO: replace `nil` with `subject` to consider exercise, guide, etc
89
- current_user&.current_immersive_context_at(nil) || Organization.current
109
+ current_immersive_context_and_content&.first || Organization.current
110
+ end
111
+
112
+ def current_immersive_context_and_content
113
+ current_user&.current_immersive_context_and_content_at(subject) || [Organization.current, nil]
90
114
  end
91
115
 
92
116
  def from_sessions?
@@ -99,11 +123,19 @@ class ApplicationController < ActionController::Base
99
123
 
100
124
  def validate_user_profile!
101
125
  unless current_user.profile_completed?
126
+ save_location_before! :profile_completion
102
127
  flash.notice = I18n.t :please_fill_profile_data
103
128
  redirect_to edit_user_path
104
129
  end
105
130
  end
106
131
 
132
+ def validate_accepted_role_terms!
133
+ if current_user&.has_role_terms_to_accept?
134
+ flash.notice = I18n.t :accept_terms_to_continue
135
+ redirect_to terms_user_path
136
+ end
137
+ end
138
+
107
139
  def set_locale!
108
140
  I18n.locale = Organization.current.locale
109
141
  end
@@ -3,6 +3,7 @@ class AssetsController < ApplicationController
3
3
  protect_from_forgery except: [:theme_stylesheet, :extension_javascript]
4
4
  skip_before_action :authorize_if_private!
5
5
  skip_before_action :validate_user_profile!
6
+ skip_before_action :validate_accepted_role_terms!
6
7
  skip_before_action :validate_active_organization!
7
8
 
8
9
  def theme_stylesheet
@@ -2,7 +2,7 @@ class BookDiscussionsController < DiscussionsController
2
2
  def terms
3
3
  @forum_terms ||= Term.forum_related_terms
4
4
  end
5
-
5
+
6
6
  private
7
7
 
8
8
  def set_debatable
@@ -2,6 +2,7 @@ require 'addressable/uri'
2
2
 
3
3
  class ChaptersController < ApplicationController
4
4
  include Mumuki::Laboratory::Controllers::Content
5
+ include Mumuki::Laboratory::Controllers::ImmersiveNavigation
5
6
 
6
7
  def show
7
8
  end
@@ -46,6 +46,10 @@ class DiscussionsController < ApplicationController
46
46
 
47
47
  private
48
48
 
49
+ def default_immersive_path_for(context)
50
+ context.forum_enabled? ? discussions_path : root_path
51
+ end
52
+
49
53
  def current_content_discussions
50
54
  @debatable.discussions_in_organization
51
55
  end
@@ -1,6 +1,7 @@
1
1
  class ExercisesController < ApplicationController
2
2
  include Mumuki::Laboratory::Controllers::Content
3
3
  include Mumuki::Laboratory::Controllers::ExerciseSeed
4
+ include Mumuki::Laboratory::Controllers::ImmersiveNavigation
4
5
 
5
6
  before_action :set_guide!, only: :show
6
7
  before_action :set_assignment!, only: :show, if: :current_user?
@@ -1,4 +1,6 @@
1
1
  class GuidesController < ApplicationController
2
+ include Mumuki::Laboratory::Controllers::ImmersiveNavigation
3
+
2
4
  def show
3
5
  redirect_to_usage Guide.find_by!(id: params[:id])
4
6
  end
@@ -6,6 +6,7 @@ class InvitationsController < ApplicationController
6
6
  before_action :set_user!
7
7
 
8
8
  skip_before_action :validate_user_profile!
9
+ skip_before_action :validate_accepted_role_terms!
9
10
  skip_before_action :authorize_if_private!
10
11
  skip_before_action :validate_active_organization!
11
12