diff --git a/lms/envs/common.py b/lms/envs/common.py index b7bce352aec99682b52fa005d0a2a66e3860bd1d..d86079f0ada9b7e17a6aff81264056c4be752bd4 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -2928,6 +2928,7 @@ ACCOUNT_VISIBILITY_CONFIGURATION = { 'profile_image', 'country', 'time_zone', + 'date_joined', 'language_proficiencies', 'bio', 'account_privacy', @@ -2946,10 +2947,10 @@ ACCOUNT_VISIBILITY_CONFIGURATION = { "admin_fields": [ "username", "email", - "date_joined", "is_active", "bio", "country", + "date_joined", "profile_image", "language_proficiencies", "name", diff --git a/lms/static/js/spec/student_account/helpers.js b/lms/static/js/spec/student_account/helpers.js index 6660e07b80c81e1b9b2d155e3e2182a1b21ae7f2..23df61438f7293fd89536504d46dd2fcd4e2cd3a 100644 --- a/lms/static/js/spec/student_account/helpers.js +++ b/lms/static/js/spec/student_account/helpers.js @@ -74,7 +74,8 @@ define(['underscore'], function(_) { year_of_birth: '3', // Note: test birth year range is a string from 0-3 requires_parental_consent: false, country: '1', - language: null, + language: 'en-US', + date_joined: 'December 17, 1995 03:24:00', bio: 'About the student', language_proficiencies: [{code: '1'}], profile_image: PROFILE_IMAGE, @@ -82,7 +83,7 @@ define(['underscore'], function(_) { }; var DEFAULT_USER_PREFERENCES_DATA = { 'pref-lang': '2', - 'time_zone': null + time_zone: 'America/New_York' }; var createAccountSettingsData = function(options) { diff --git a/lms/static/js/spec/views/fields_spec.js b/lms/static/js/spec/views/fields_spec.js index 8ecb48782aaffcab527db5719f70064f9bba3580..f2dd4695bfab9df6b6dd0e8615681fc185117690 100644 --- a/lms/static/js/spec/views/fields_spec.js +++ b/lms/static/js/spec/views/fields_spec.js @@ -326,19 +326,6 @@ define(['backbone', 'jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helper expect(view.$('.u-field-value > a .u-field-link-title-' + view.options.valueAttribute).text().trim()).toBe(fieldData.linkTitle); }); - it('correctly renders LinkFieldView', function() { - var fieldData = FieldViewsSpecHelpers.createFieldData(FieldViews.LinkFieldView, { - title: 'Title', - linkTitle: 'Link title', - helpMessage: 'Click the link.', - valueAttribute: 'password-reset' - }); - var view = new FieldViews.LinkFieldView(fieldData).render(); - - FieldViewsSpecHelpers.expectTitleAndMessageToContain(view, fieldData.title, fieldData.helpMessage); - expect(view.$('.u-field-value > a .u-field-link-title-' + view.options.valueAttribute).text().trim()).toBe(fieldData.linkTitle); - }); - it("can't persist changes if persistChanges is off", function() { requests = AjaxHelpers.requests(this); var fieldClasses = [ @@ -350,5 +337,21 @@ define(['backbone', 'jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helper FieldViewsSpecHelpers.verifyPersistence(fieldClasses[i], requests); } }); + + it('correctly renders DateFieldView', function() { + var fieldData = FieldViewsSpecHelpers.createFieldData(FieldViews.DateFieldView, { + title: 'Title', + helpMessage: '', + dateFormat: 'MMM YYYY', + valueAttribute: 'date_joined', + userLanguage: 'en-US', + userTimezone: 'America/New_York' + }), + joinDate = new Date(1990, 0, 15), + view; + fieldData.model.set({date_joined: joinDate.toDateString()}); + view = new FieldViews.DateFieldView(fieldData).render(); + expect(view.$('.u-field-value').text().trim()).toBe('Jan 1990'); + }); }); }); diff --git a/lms/static/js/views/fields.js b/lms/static/js/views/fields.js index 878333df28ec33d8b9e34007a2c4775d9b54c165..06215c8280d7e74698109ed0ddefdea5c8368900 100644 --- a/lms/static/js/views/fields.js +++ b/lms/static/js/views/fields.js @@ -3,13 +3,14 @@ define([ 'gettext', 'jquery', 'underscore', 'backbone', 'edx-ui-toolkit/js/utils/html-utils', + 'edx-ui-toolkit/js/utils/date-utils', 'text!templates/fields/field_readonly.underscore', 'text!templates/fields/field_dropdown.underscore', 'text!templates/fields/field_link.underscore', 'text!templates/fields/field_text.underscore', 'text!templates/fields/field_textarea.underscore', 'backbone-super' - ], function(gettext, $, _, Backbone, HtmlUtils, + ], function(gettext, $, _, Backbone, HtmlUtils, DateUtils, field_readonly_template, field_dropdown_template, field_link_template, @@ -313,6 +314,38 @@ } }); + FieldViews.DateFieldView = FieldViews.ReadonlyFieldView.extend({ + + fieldType: 'date', + + timezoneFormattedDate: function() { + var context; + context = { + datetime: new Date(this.modelValue()), + language: this.options.userLanguage, + timezone: this.options.userTimezone, + format: this.options.dateFormat + }; + return DateUtils.localize(context); + }, + + render: function() { + HtmlUtils.setHtml(this.$el, HtmlUtils.template(this.fieldTemplate)({ + id: this.options.valueAttribute, + title: this.options.title, + screenReaderTitle: this.options.screenReaderTitle || this.options.title, + value: this.timezoneFormattedDate(), + message: this.helpMessage + })); + this.delegateEvents(); + return this; + }, + + updateValueInField: function() { + this.$('.u-field-value ').text(this.timezoneFormattedDate()); + } + }); + FieldViews.TextFieldView = FieldViews.EditableFieldView.extend({ fieldType: 'text', diff --git a/lms/static/sass/features/_learner-profile.scss b/lms/static/sass/features/_learner-profile.scss index af0d1c400cee7467749522bf6ae680535caf2d51..c5ab800d33d7a055b08af77e45c8f79bfeb158dc 100644 --- a/lms/static/sass/features/_learner-profile.scss +++ b/lms/static/sass/features/_learner-profile.scss @@ -235,7 +235,7 @@ } .u-field-value-readonly { - @extend %t-weight3; + font-weight: 500; font-family: $sans-serif; color: $darkest-base-font-color; } @@ -245,6 +245,15 @@ display: block; } + &:not(.u-field-readonly):not(:last-child) { + padding-bottom: $baseline/4; + border-bottom: 1px solid $gray-lighter; + + &:hover.mode-placeholder { + padding-bottom: $baseline/5; + border-bottom: 2px dashed $link-color; + } + } &.u-field-dropdown { position: relative; @@ -252,15 +261,6 @@ cursor: pointer; } - &:not(:last-child) { - padding-bottom: $baseline/4; - border-bottom: 1px solid $gray-lighter; - - &:hover.mode-placeholder { - padding-bottom: $baseline/5; - border-bottom: 2px dashed $link-color; - } - } } } diff --git a/openedx/core/djangoapps/user_api/accounts/tests/test_views.py b/openedx/core/djangoapps/user_api/accounts/tests/test_views.py index 12d911b30624205bdfed06b796b93c35886490ca..7622d5fa551f28c7ca8107b4e26317d73fb67a1f 100644 --- a/openedx/core/djangoapps/user_api/accounts/tests/test_views.py +++ b/openedx/core/djangoapps/user_api/accounts/tests/test_views.py @@ -222,7 +222,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase): Verify that the shareable fields from the account are returned """ data = response.data - self.assertEqual(8, len(data)) + self.assertEqual(9, len(data)) self.assertEqual(self.user.username, data["username"]) self.assertEqual("US", data["country"]) self._verify_profile_image_data(data, True) diff --git a/openedx/features/learner_profile/static/learner_profile/js/learner_profile_factory.js b/openedx/features/learner_profile/static/learner_profile/js/learner_profile_factory.js index 7b4b657461da9a319378510d8a27054613c298a9..3cb95173c7811204d50fab89e684c81ed050e210 100644 --- a/openedx/features/learner_profile/static/learner_profile/js/learner_profile_factory.js +++ b/openedx/features/learner_profile/static/learner_profile/js/learner_profile_factory.js @@ -103,6 +103,18 @@ }); sectionOneFieldViews = [ + new FieldsView.DateFieldView({ + title: gettext('Joined'), + titleVisible: true, + model: accountSettingsModel, + screenReaderTitle: gettext('Joined Date'), + valueAttribute: 'date_joined', + helpMessage: '', + userLanguage: accountSettingsModel.get('language'), + userTimezone: accountPreferencesModel.get('time_zone'), + dateFormat: 'MMMM YYYY' // not localized, but hopefully ok. + }), + new FieldsView.DropdownFieldView({ title: gettext('Location'), titleVisible: true, diff --git a/openedx/features/learner_profile/static/learner_profile/js/spec/views/learner_profile_view_spec.js b/openedx/features/learner_profile/static/learner_profile/js/spec/views/learner_profile_view_spec.js index fe802b43c475cc0db428e09d7e442e6a84e38b83..8e9a33d8e428333060887be5220329ce543e2608 100644 --- a/openedx/features/learner_profile/static/learner_profile/js/spec/views/learner_profile_view_spec.js +++ b/openedx/features/learner_profile/static/learner_profile/js/spec/views/learner_profile_view_spec.js @@ -103,6 +103,12 @@ define( valueAttribute: 'language_proficiencies', options: Helpers.FIELD_OPTIONS, helpMessage: '' + }), + + new FieldViews.DateFieldView({ + model: accountSettingsModel, + valueAttribute: 'date_joined', + helpMessage: '' }) ]; diff --git a/openedx/features/learner_profile/static/learner_profile/js/spec_helpers/helpers.js b/openedx/features/learner_profile/static/learner_profile/js/spec_helpers/helpers.js index 9833f4dab1301b357b75781b302448ac639db121..76022f9901ebd475ab38fd685b12b80bd7c88085 100644 --- a/openedx/features/learner_profile/static/learner_profile/js/spec_helpers/helpers.js +++ b/openedx/features/learner_profile/static/learner_profile/js/spec_helpers/helpers.js @@ -12,6 +12,8 @@ define(['underscore', 'URI', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers' if ('fieldValue' in view || 'imageUrl' in view) { if ('imageUrl' in view) { expect($($element.find('.image-frame')[0]).attr('src')).toBe(view.imageUrl()); + } else if (view.fieldType === 'date') { + expect(view.fieldValue()).toBe(view.timezoneFormattedDate()); } else if (view.fieldValue()) { expect(view.fieldValue()).toBe(view.modelValue()); } else if ('optionForValue' in view) { @@ -41,7 +43,7 @@ define(['underscore', 'URI', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers' var expectSectionOneTobeRendered = function(learnerProfileView) { var sectionOneFieldElements = $(learnerProfileView.$('.wrapper-profile-section-one')).find('.u-field'); - expect(sectionOneFieldElements.length).toBe(5); + expect(sectionOneFieldElements.length).toBe(6); expectProfileElementContainsField(sectionOneFieldElements[0], learnerProfileView.options.profileImageFieldView); expectProfileElementContainsField(sectionOneFieldElements[1], learnerProfileView.options.usernameFieldView); expectProfileElementContainsField(sectionOneFieldElements[2], learnerProfileView.options.nameFieldView);