feat!: Legacy account, profile, order history removal (#36219)

* feat!: Legacy account, profile, order history removal

This removes the legacy account and profile applications, and the order
history page. This is primarily a reapplication of #31893, which was
rolled back due to prior blockers.

FIXES: APER-3884
FIXES: openedx/public-engineering#71


Co-authored-by: Muhammad Abdullah Waheed <42172960+abdullahwaheed@users.noreply.github.com>
Co-authored-by: Bilal Qamar <59555732+BilalQamar95@users.noreply.github.com>
This commit is contained in:
Deborah Kaplan
2025-02-10 14:39:13 -05:00
committed by GitHub
parent 36c16d6952
commit 29de9b2dc4
73 changed files with 752 additions and 7391 deletions

View File

@@ -1,334 +0,0 @@
define(['backbone',
'jquery',
'underscore',
'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers',
'common/js/spec_helpers/template_helpers',
'js/spec/views/fields_helpers',
'js/spec/student_account/helpers',
'js/spec/student_account/account_settings_fields_helpers',
'js/student_account/views/account_settings_factory',
'js/student_account/views/account_settings_view'
],
function(Backbone, $, _, AjaxHelpers, TemplateHelpers, FieldViewsSpecHelpers, Helpers,
AccountSettingsFieldViewSpecHelpers, AccountSettingsPage) {
'use strict';
describe('edx.user.AccountSettingsFactory', function() {
var createAccountSettingsPage = function() {
var context = AccountSettingsPage(
Helpers.FIELDS_DATA,
false,
[],
Helpers.AUTH_DATA,
Helpers.PASSWORD_RESET_SUPPORT_LINK,
Helpers.USER_ACCOUNTS_API_URL,
Helpers.USER_PREFERENCES_API_URL,
1,
Helpers.PLATFORM_NAME,
Helpers.CONTACT_EMAIL,
true,
Helpers.ENABLE_COPPA_COMPLIANCE
);
return context.accountSettingsView;
};
var requests;
beforeEach(function() {
setFixtures('<div class="wrapper-account-settings"></div>');
});
it('shows loading error when UserAccountModel fails to load', function() {
requests = AjaxHelpers.requests(this);
var accountSettingsView = createAccountSettingsPage();
Helpers.expectLoadingErrorIsVisible(accountSettingsView, false);
var request = requests[0];
expect(request.method).toBe('GET');
expect(request.url).toBe(Helpers.USER_ACCOUNTS_API_URL);
AjaxHelpers.respondWithError(requests, 500);
Helpers.expectLoadingErrorIsVisible(accountSettingsView, true);
});
it('shows loading error when UserPreferencesModel fails to load', function() {
requests = AjaxHelpers.requests(this);
var accountSettingsView = createAccountSettingsPage();
Helpers.expectLoadingErrorIsVisible(accountSettingsView, false);
var request = requests[0];
expect(request.method).toBe('GET');
expect(request.url).toBe(Helpers.USER_ACCOUNTS_API_URL);
AjaxHelpers.respondWithJson(requests, Helpers.createAccountSettingsData());
Helpers.expectLoadingErrorIsVisible(accountSettingsView, false);
request = requests[1];
expect(request.method).toBe('GET');
expect(request.url).toBe('/api/user/v1/preferences/time_zones/?country_code=1');
AjaxHelpers.respondWithJson(requests, Helpers.TIME_ZONE_RESPONSE);
request = requests[2];
expect(request.method).toBe('GET');
expect(request.url).toBe(Helpers.USER_PREFERENCES_API_URL);
AjaxHelpers.respondWithError(requests, 500);
Helpers.expectLoadingErrorIsVisible(accountSettingsView, true);
});
it('renders fields after the models are successfully fetched', function() {
requests = AjaxHelpers.requests(this);
var accountSettingsView = createAccountSettingsPage();
Helpers.expectLoadingErrorIsVisible(accountSettingsView, false);
AjaxHelpers.respondWithJson(requests, Helpers.createAccountSettingsData());
AjaxHelpers.respondWithJson(requests, Helpers.TIME_ZONE_RESPONSE);
AjaxHelpers.respondWithJson(requests, Helpers.createUserPreferencesData());
accountSettingsView.render();
Helpers.expectLoadingErrorIsVisible(accountSettingsView, false);
Helpers.expectSettingsSectionsAndFieldsToBeRendered(accountSettingsView);
});
it('expects all fields to behave correctly', function() {
var i, view;
requests = AjaxHelpers.requests(this);
var accountSettingsView = createAccountSettingsPage();
AjaxHelpers.respondWithJson(requests, Helpers.createAccountSettingsData());
AjaxHelpers.respondWithJson(requests, Helpers.TIME_ZONE_RESPONSE);
AjaxHelpers.respondWithJson(requests, Helpers.createUserPreferencesData());
AjaxHelpers.respondWithJson(requests, {}); // Page viewed analytics event
var sectionsData = accountSettingsView.options.tabSections.aboutTabSections;
expect(sectionsData[0].fields.length).toBe(7);
var textFields = [sectionsData[0].fields[1], sectionsData[0].fields[2]];
for (i = 0; i < textFields.length; i++) {
view = textFields[i].view;
FieldViewsSpecHelpers.verifyTextField(view, {
title: view.options.title,
valueAttribute: view.options.valueAttribute,
helpMessage: view.options.helpMessage,
validValue: 'My Name',
invalidValue1: '',
invalidValue2: '@',
validationError: 'Think again!',
defaultValue: ''
}, requests);
}
expect(sectionsData[1].fields.length).toBe(4);
var dropdownFields = [
sectionsData[1].fields[0],
sectionsData[1].fields[1],
sectionsData[1].fields[2]
];
_.each(dropdownFields, function(field) {
// eslint-disable-next-line no-shadow
var view = field.view;
FieldViewsSpecHelpers.verifyDropDownField(view, {
title: view.options.title,
valueAttribute: view.options.valueAttribute,
helpMessage: '',
validValue: Helpers.FIELD_OPTIONS[1][0],
invalidValue1: Helpers.FIELD_OPTIONS[2][0],
invalidValue2: Helpers.FIELD_OPTIONS[3][0],
validationError: 'Nope, this will not do!',
defaultValue: null
}, requests);
});
});
});
describe('edx.user.AccountSettingsFactory', function() {
var createEnterpriseLearnerAccountSettingsPage = function() {
var context = AccountSettingsPage(
Helpers.FIELDS_DATA,
false,
[],
Helpers.AUTH_DATA,
Helpers.PASSWORD_RESET_SUPPORT_LINK,
Helpers.USER_ACCOUNTS_API_URL,
Helpers.USER_PREFERENCES_API_URL,
1,
Helpers.PLATFORM_NAME,
Helpers.CONTACT_EMAIL,
true,
Helpers.ENABLE_COPPA_COMPLIANCE,
'',
Helpers.SYNC_LEARNER_PROFILE_DATA,
Helpers.ENTERPRISE_NAME,
Helpers.ENTERPRISE_READ_ONLY_ACCOUNT_FIELDS,
Helpers.EDX_SUPPORT_URL
);
return context.accountSettingsView;
};
var requests;
var accountInfoTab = {
BASIC_ACCOUNT_INFORMATION: 0,
ADDITIONAL_INFORMATION: 1
};
var basicAccountInfoFields = {
USERNAME: 0,
FULL_NAME: 1,
EMAIL_ADDRESS: 2,
PASSWORD: 3,
LANGUAGE: 4,
COUNTRY: 5,
TIMEZONE: 6
};
var additionalInfoFields = {
EDUCATION: 0,
GENDER: 1,
YEAR_OF_BIRTH: 2,
PREFERRED_LANGUAGE: 3
};
beforeEach(function() {
setFixtures('<div class="wrapper-account-settings"></div>');
});
it('shows loading error when UserAccountModel fails to load for enterprise learners', function() {
var accountSettingsView, request;
requests = AjaxHelpers.requests(this);
accountSettingsView = createEnterpriseLearnerAccountSettingsPage();
Helpers.expectLoadingErrorIsVisible(accountSettingsView, false);
request = requests[0];
expect(request.method).toBe('GET');
expect(request.url).toBe(Helpers.USER_ACCOUNTS_API_URL);
AjaxHelpers.respondWithError(requests, 500);
Helpers.expectLoadingErrorIsVisible(accountSettingsView, true);
});
it('shows loading error when UserPreferencesModel fails to load for enterprise learners', function() {
var accountSettingsView, request;
requests = AjaxHelpers.requests(this);
accountSettingsView = createEnterpriseLearnerAccountSettingsPage();
Helpers.expectLoadingErrorIsVisible(accountSettingsView, false);
request = requests[0];
expect(request.method).toBe('GET');
expect(request.url).toBe(Helpers.USER_ACCOUNTS_API_URL);
AjaxHelpers.respondWithJson(requests, Helpers.createAccountSettingsData());
Helpers.expectLoadingErrorIsVisible(accountSettingsView, false);
request = requests[1];
expect(request.method).toBe('GET');
expect(request.url).toBe('/api/user/v1/preferences/time_zones/?country_code=1');
AjaxHelpers.respondWithJson(requests, Helpers.TIME_ZONE_RESPONSE);
request = requests[2];
expect(request.method).toBe('GET');
expect(request.url).toBe(Helpers.USER_PREFERENCES_API_URL);
AjaxHelpers.respondWithError(requests, 500);
Helpers.expectLoadingErrorIsVisible(accountSettingsView, true);
});
it('renders fields after the models are successfully fetched for enterprise learners', function() {
var accountSettingsView;
requests = AjaxHelpers.requests(this);
accountSettingsView = createEnterpriseLearnerAccountSettingsPage();
Helpers.expectLoadingErrorIsVisible(accountSettingsView, false);
AjaxHelpers.respondWithJson(requests, Helpers.createAccountSettingsData());
AjaxHelpers.respondWithJson(requests, Helpers.TIME_ZONE_RESPONSE);
AjaxHelpers.respondWithJson(requests, Helpers.createUserPreferencesData());
accountSettingsView.render();
Helpers.expectLoadingErrorIsVisible(accountSettingsView, false);
Helpers.expectSettingsSectionsAndFieldsToBeRenderedWithMessage(accountSettingsView);
});
it('expects all fields to behave correctly for enterprise learners', function() {
var accountSettingsView, i, view, sectionsData, textFields, dropdownFields;
requests = AjaxHelpers.requests(this);
accountSettingsView = createEnterpriseLearnerAccountSettingsPage();
AjaxHelpers.respondWithJson(requests, Helpers.createAccountSettingsData());
AjaxHelpers.respondWithJson(requests, Helpers.TIME_ZONE_RESPONSE);
AjaxHelpers.respondWithJson(requests, Helpers.createUserPreferencesData());
AjaxHelpers.respondWithJson(requests, {}); // Page viewed analytics event
sectionsData = accountSettingsView.options.tabSections.aboutTabSections;
expect(sectionsData[accountInfoTab.BASIC_ACCOUNT_INFORMATION].fields.length).toBe(7);
// Verify that username, name and email fields are readonly
textFields = [
sectionsData[accountInfoTab.BASIC_ACCOUNT_INFORMATION].fields[basicAccountInfoFields.USERNAME],
sectionsData[accountInfoTab.BASIC_ACCOUNT_INFORMATION].fields[basicAccountInfoFields.FULL_NAME],
sectionsData[accountInfoTab.BASIC_ACCOUNT_INFORMATION].fields[basicAccountInfoFields.EMAIL_ADDRESS]
];
for (i = 0; i < textFields.length; i++) {
view = textFields[i].view;
FieldViewsSpecHelpers.verifyReadonlyTextField(view, {
title: view.options.title,
valueAttribute: view.options.valueAttribute,
helpMessage: view.options.helpMessage,
validValue: 'My Name',
defaultValue: ''
}, requests);
}
// Verify un-editable country dropdown field
view = sectionsData[
accountInfoTab.BASIC_ACCOUNT_INFORMATION
].fields[basicAccountInfoFields.COUNTRY].view;
FieldViewsSpecHelpers.verifyReadonlyDropDownField(view, {
title: view.options.title,
valueAttribute: view.options.valueAttribute,
helpMessage: '',
validValue: Helpers.FIELD_OPTIONS[1][0],
editable: 'never',
defaultValue: null
});
expect(sectionsData[accountInfoTab.ADDITIONAL_INFORMATION].fields.length).toBe(4);
dropdownFields = [
sectionsData[accountInfoTab.ADDITIONAL_INFORMATION].fields[additionalInfoFields.EDUCATION],
sectionsData[accountInfoTab.ADDITIONAL_INFORMATION].fields[additionalInfoFields.GENDER],
sectionsData[accountInfoTab.ADDITIONAL_INFORMATION].fields[additionalInfoFields.YEAR_OF_BIRTH]
];
_.each(dropdownFields, function(field) {
view = field.view;
FieldViewsSpecHelpers.verifyDropDownField(view, {
title: view.options.title,
valueAttribute: view.options.valueAttribute,
helpMessage: '',
validValue: Helpers.FIELD_OPTIONS[1][0], // dummy option for dropdown field
invalidValue1: Helpers.FIELD_OPTIONS[2][0], // dummy option for dropdown field
invalidValue2: Helpers.FIELD_OPTIONS[3][0], // dummy option for dropdown field
validationError: 'Nope, this will not do!',
defaultValue: null
}, requests);
});
});
});
});

View File

@@ -1,34 +0,0 @@
define(['backbone',
'jquery',
'underscore',
'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers',
'common/js/spec_helpers/template_helpers',
'js/spec/views/fields_helpers',
'string_utils'],
function(Backbone, $, _, AjaxHelpers, TemplateHelpers, FieldViewsSpecHelpers) {
'use strict';
var verifyAuthField = function(view, data, requests) {
var selector = '.u-field-value .u-field-link-title-' + view.options.valueAttribute;
spyOn(view, 'redirect_to');
FieldViewsSpecHelpers.expectTitleAndMessageToContain(view, data.title, data.helpMessage);
expect(view.$(selector).text().trim()).toBe('Unlink This Account');
view.$(selector).click();
FieldViewsSpecHelpers.expectMessageContains(view, 'Unlinking');
AjaxHelpers.expectRequest(requests, 'POST', data.disconnectUrl);
AjaxHelpers.respondWithNoContent(requests);
expect(view.$(selector).text().trim()).toBe('Link Your Account');
FieldViewsSpecHelpers.expectMessageContains(view, 'Successfully unlinked.');
view.$(selector).click();
FieldViewsSpecHelpers.expectMessageContains(view, 'Linking');
expect(view.redirect_to).toHaveBeenCalledWith(data.connectUrl);
};
return {
verifyAuthField: verifyAuthField
};
});

View File

@@ -1,216 +0,0 @@
define(['backbone',
'jquery',
'underscore',
'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers',
'common/js/spec_helpers/template_helpers',
'js/student_account/models/user_account_model',
'js/views/fields',
'js/spec/views/fields_helpers',
'js/spec/student_account/account_settings_fields_helpers',
'js/student_account/views/account_settings_fields',
'js/student_account/models/user_account_model',
'string_utils'],
function(Backbone, $, _, AjaxHelpers, TemplateHelpers, UserAccountModel, FieldViews, FieldViewsSpecHelpers,
AccountSettingsFieldViewSpecHelpers, AccountSettingsFieldViews) {
'use strict';
describe('edx.AccountSettingsFieldViews', function() {
var requests,
timerCallback, // eslint-disable-line no-unused-vars
data;
beforeEach(function() {
timerCallback = jasmine.createSpy('timerCallback');
jasmine.clock().install();
});
afterEach(function() {
jasmine.clock().uninstall();
});
it('sends request to reset password on clicking link in PasswordFieldView', function() {
requests = AjaxHelpers.requests(this);
var fieldData = FieldViewsSpecHelpers.createFieldData(AccountSettingsFieldViews.PasswordFieldView, {
linkHref: '/password_reset',
emailAttribute: 'email',
valueAttribute: 'password'
});
var view = new AccountSettingsFieldViews.PasswordFieldView(fieldData).render();
expect(view.$('.u-field-value > button').is(':disabled')).toBe(false);
view.$('.u-field-value > button').click();
expect(view.$('.u-field-value > button').is(':disabled')).toBe(true);
AjaxHelpers.expectRequest(requests, 'POST', '/password_reset', 'email=legolas%40woodland.middlearth');
AjaxHelpers.respondWithJson(requests, {success: 'true'});
FieldViewsSpecHelpers.expectMessageContains(
view,
"We've sent a message to legolas@woodland.middlearth. "
+ 'Click the link in the message to reset your password.'
);
});
it('update time zone dropdown after country dropdown changes', function() {
var baseSelector = '.u-field-value > select';
var groupsSelector = baseSelector + '> optgroup';
var groupOptionsSelector = groupsSelector + '> option';
var timeZoneData = FieldViewsSpecHelpers.createFieldData(AccountSettingsFieldViews.TimeZoneFieldView, {
valueAttribute: 'time_zone',
groupOptions: [{
groupTitle: gettext('All Time Zones'),
selectOptions: FieldViewsSpecHelpers.SELECT_OPTIONS,
nullValueOptionLabel: 'Default (Local Time Zone)'
}],
persistChanges: true,
required: true
});
var countryData = FieldViewsSpecHelpers.createFieldData(AccountSettingsFieldViews.DropdownFieldView, {
valueAttribute: 'country',
options: [['KY', 'Cayman Islands'], ['CA', 'Canada'], ['GY', 'Guyana']],
persistChanges: true
});
var countryChange = {country: 'GY'};
var timeZoneChange = {time_zone: 'Pacific/Kosrae'};
var timeZoneView = new AccountSettingsFieldViews.TimeZoneFieldView(timeZoneData).render();
var countryView = new AccountSettingsFieldViews.DropdownFieldView(countryData).render();
requests = AjaxHelpers.requests(this);
timeZoneView.listenToCountryView(countryView);
// expect time zone dropdown to have single subheader ('All Time Zones')
expect(timeZoneView.$(groupsSelector).length).toBe(1);
expect(timeZoneView.$(groupOptionsSelector).length).toBe(3);
expect(timeZoneView.$(groupOptionsSelector)[0].value).toBe(FieldViewsSpecHelpers.SELECT_OPTIONS[0][0]);
// change country
countryView.$(baseSelector).val(countryChange[countryData.valueAttribute]).change();
countryView.$(baseSelector).focusout();
FieldViewsSpecHelpers.expectAjaxRequestWithData(requests, countryChange);
AjaxHelpers.respondWithJson(requests, {success: 'true'});
AjaxHelpers.expectRequest(
requests,
'GET',
'/api/user/v1/preferences/time_zones/?country_code=GY'
);
AjaxHelpers.respondWithJson(requests, [
{time_zone: 'America/Guyana', description: 'America/Guyana (ECT, UTC-0500)'},
{time_zone: 'Pacific/Kosrae', description: 'Pacific/Kosrae (KOST, UTC+1100)'}
]);
// expect time zone dropdown to have two subheaders (country/all time zone sub-headers) with new values
expect(timeZoneView.$(groupsSelector).length).toBe(2);
expect(timeZoneView.$(groupOptionsSelector).length).toBe(6);
expect(timeZoneView.$(groupOptionsSelector)[0].value).toBe('America/Guyana');
// select time zone option from option
timeZoneView.$(baseSelector).val(timeZoneChange[timeZoneData.valueAttribute]).change();
timeZoneView.$(baseSelector).focusout();
FieldViewsSpecHelpers.expectAjaxRequestWithData(requests, timeZoneChange);
AjaxHelpers.respondWithJson(requests, {success: 'true'});
timeZoneView.render();
// expect time zone dropdown to have three subheaders (currently selected/country/all time zones)
expect(timeZoneView.$(groupsSelector).length).toBe(3);
expect(timeZoneView.$(groupOptionsSelector).length).toBe(6);
expect(timeZoneView.$(groupOptionsSelector)[0].value).toBe('Pacific/Kosrae');
});
it('sends request to /i18n/setlang/ after changing language in LanguagePreferenceFieldView', function() {
requests = AjaxHelpers.requests(this);
var selector = '.u-field-value > select';
var fieldData = FieldViewsSpecHelpers.createFieldData(AccountSettingsFieldViews.DropdownFieldView, {
valueAttribute: 'language',
options: FieldViewsSpecHelpers.SELECT_OPTIONS,
persistChanges: true
});
var view = new AccountSettingsFieldViews.LanguagePreferenceFieldView(fieldData).render();
data = {language: FieldViewsSpecHelpers.SELECT_OPTIONS[2][0]};
view.$(selector).val(data[fieldData.valueAttribute]).change();
view.$(selector).focusout();
FieldViewsSpecHelpers.expectAjaxRequestWithData(requests, data);
AjaxHelpers.respondWithNoContent(requests);
AjaxHelpers.expectRequest(
requests,
'POST',
'/i18n/setlang/',
$.param({
language: data[fieldData.valueAttribute],
next: window.location.href
})
);
// Django will actually respond with a 302 redirect, but that would cause a page load during these
// unittests. 204 should work fine for testing.
AjaxHelpers.respondWithNoContent(requests);
FieldViewsSpecHelpers.expectMessageContains(view, 'Your changes have been saved.');
data = {language: FieldViewsSpecHelpers.SELECT_OPTIONS[1][0]};
view.$(selector).val(data[fieldData.valueAttribute]).change();
view.$(selector).focusout();
FieldViewsSpecHelpers.expectAjaxRequestWithData(requests, data);
AjaxHelpers.respondWithNoContent(requests);
AjaxHelpers.expectRequest(
requests,
'POST',
'/i18n/setlang/',
$.param({
language: data[fieldData.valueAttribute],
next: window.location.href
})
);
AjaxHelpers.respondWithError(requests, 500);
FieldViewsSpecHelpers.expectMessageContains(
view,
'You must sign out and sign back in before your language changes take effect.'
);
});
it('reads and saves the value correctly for LanguageProficienciesFieldView', function() {
requests = AjaxHelpers.requests(this);
var selector = '.u-field-value > select';
var fieldData = FieldViewsSpecHelpers.createFieldData(AccountSettingsFieldViews.DropdownFieldView, {
valueAttribute: 'language_proficiencies',
options: FieldViewsSpecHelpers.SELECT_OPTIONS,
persistChanges: true
});
fieldData.model.set({language_proficiencies: [{code: FieldViewsSpecHelpers.SELECT_OPTIONS[0][0]}]});
var view = new AccountSettingsFieldViews.LanguageProficienciesFieldView(fieldData).render();
expect(view.modelValue()).toBe(FieldViewsSpecHelpers.SELECT_OPTIONS[0][0]);
data = {language_proficiencies: [{code: FieldViewsSpecHelpers.SELECT_OPTIONS[1][0]}]};
view.$(selector).val(FieldViewsSpecHelpers.SELECT_OPTIONS[1][0]).change();
view.$(selector).focusout();
FieldViewsSpecHelpers.expectAjaxRequestWithData(requests, data);
AjaxHelpers.respondWithNoContent(requests);
});
it('correctly links and unlinks from AuthFieldView', function() {
requests = AjaxHelpers.requests(this);
var fieldData = FieldViewsSpecHelpers.createFieldData(FieldViews.LinkFieldView, {
title: 'Yet another social network',
helpMessage: '',
valueAttribute: 'auth-yet-another',
connected: true,
acceptsLogins: 'true',
connectUrl: 'yetanother.com/auth/connect',
disconnectUrl: 'yetanother.com/auth/disconnect'
});
var view = new AccountSettingsFieldViews.AuthFieldView(fieldData).render();
AccountSettingsFieldViewSpecHelpers.verifyAuthField(view, fieldData, requests);
});
});
});

View File

@@ -1,91 +0,0 @@
define(['backbone',
'jquery',
'underscore',
'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers',
'common/js/spec_helpers/template_helpers',
'js/spec/student_account/helpers',
'js/views/fields',
'js/student_account/models/user_account_model',
'js/student_account/views/account_settings_view'
],
function(Backbone, $, _, AjaxHelpers, TemplateHelpers, Helpers, FieldViews, UserAccountModel,
AccountSettingsView) {
'use strict';
describe('edx.user.AccountSettingsView', function() {
var createAccountSettingsView = function() {
var model = new UserAccountModel();
model.set(Helpers.createAccountSettingsData());
var aboutSectionsData = [
{
title: 'Basic Account Information',
messageType: 'info',
message: 'Your profile settings are managed by Test Enterprise. '
+ 'Contact your administrator or <a href="https://support.edx.org/">edX Support</a> for help.',
fields: [
{
view: new FieldViews.ReadonlyFieldView({
model: model,
title: 'Username',
valueAttribute: 'username'
})
},
{
view: new FieldViews.TextFieldView({
model: model,
title: 'Full Name',
valueAttribute: 'name'
})
}
]
},
{
title: 'Additional Information',
fields: [
{
view: new FieldViews.DropdownFieldView({
model: model,
title: 'Education Completed',
valueAttribute: 'level_of_education',
options: Helpers.FIELD_OPTIONS
})
}
]
}
];
var accountSettingsView = new AccountSettingsView({
el: $('.wrapper-account-settings'),
model: model,
tabSections: {
aboutTabSections: aboutSectionsData
}
});
return accountSettingsView;
};
beforeEach(function() {
setFixtures('<div class="wrapper-account-settings"></div>');
});
it('shows loading error correctly', function() {
var accountSettingsView = createAccountSettingsView();
accountSettingsView.render();
Helpers.expectLoadingErrorIsVisible(accountSettingsView, false);
accountSettingsView.showLoadingError();
Helpers.expectLoadingErrorIsVisible(accountSettingsView, true);
});
it('renders all fields as expected', function() {
var accountSettingsView = createAccountSettingsView();
accountSettingsView.render();
Helpers.expectLoadingErrorIsVisible(accountSettingsView, false);
Helpers.expectSettingsSectionsAndFieldsToBeRendered(accountSettingsView);
});
});
});

View File

@@ -1,48 +0,0 @@
// eslint-disable-next-line no-shadow-restricted-names
(function(define, undefined) {
'use strict';
define([
'gettext',
'jquery',
'underscore',
'backbone',
'edx-ui-toolkit/js/utils/html-utils',
'text!templates/student_account/account_settings_section.underscore'
], function(gettext, $, _, Backbone, HtmlUtils, sectionTemplate) {
var AccountSectionView = Backbone.View.extend({
initialize: function(options) {
this.options = options;
_.bindAll(this, 'render', 'renderFields');
},
render: function() {
HtmlUtils.setHtml(
this.$el,
HtmlUtils.template(sectionTemplate)({
HtmlUtils: HtmlUtils,
sections: this.options.sections,
tabName: this.options.tabName,
tabLabel: this.options.tabLabel
})
);
this.renderFields();
},
renderFields: function() {
var view = this;
_.each(view.$('.' + view.options.tabName + '-section-body'), function(sectionEl, index) {
_.each(view.options.sections[index].fields, function(field) {
$(sectionEl).append(field.view.render().el);
});
});
return this;
}
});
return AccountSectionView;
});
}).call(this, define || RequireJS.define);

View File

@@ -1,495 +0,0 @@
// eslint-disable-next-line no-shadow-restricted-names
(function(define, undefined) {
'use strict';
define([
'gettext', 'jquery', 'underscore', 'backbone', 'logger',
'js/student_account/models/user_account_model',
'js/student_account/models/user_preferences_model',
'js/student_account/views/account_settings_fields',
'js/student_account/views/account_settings_view',
'edx-ui-toolkit/js/utils/string-utils',
'edx-ui-toolkit/js/utils/html-utils'
], function(gettext, $, _, Backbone, Logger, UserAccountModel, UserPreferencesModel,
AccountSettingsFieldViews, AccountSettingsView, StringUtils, HtmlUtils) {
return function(
fieldsData,
disableOrderHistoryTab,
ordersHistoryData,
authData,
passwordResetSupportUrl,
userAccountsApiUrl,
userPreferencesApiUrl,
accountUserId,
platformName,
contactEmail,
allowEmailChange,
enableCoppaCompliance,
socialPlatforms,
syncLearnerProfileData,
enterpriseName,
enterpriseReadonlyAccountFields,
edxSupportUrl,
extendedProfileFields,
displayAccountDeletion,
isSecondaryEmailFeatureEnabled,
betaLanguage
) {
var $accountSettingsElement, userAccountModel, userPreferencesModel, aboutSectionsData,
accountsSectionData, ordersSectionData, accountSettingsView, showAccountSettingsPage,
showLoadingError, orderNumber, getUserField, userFields, timeZoneDropdownField, countryDropdownField,
emailFieldView, secondaryEmailFieldView, socialFields, accountDeletionFields, platformData,
aboutSectionMessageType, aboutSectionMessage, fullnameFieldView, countryFieldView,
fullNameFieldData, emailFieldData, secondaryEmailFieldData, countryFieldData, additionalFields,
fieldItem, emailFieldViewIndex, focusId, yearOfBirthViewIndex, levelOfEducationFieldData,
tabIndex = 0;
$accountSettingsElement = $('.wrapper-account-settings');
userAccountModel = new UserAccountModel();
userAccountModel.url = userAccountsApiUrl;
userPreferencesModel = new UserPreferencesModel();
userPreferencesModel.url = userPreferencesApiUrl;
if (syncLearnerProfileData && enterpriseName) {
aboutSectionMessageType = 'info';
aboutSectionMessage = HtmlUtils.interpolateHtml(
gettext('Your profile settings are managed by {enterprise_name}. Contact your administrator or {link_start}edX Support{link_end} for help.'), // eslint-disable-line max-len
{
enterprise_name: enterpriseName,
link_start: HtmlUtils.HTML(
StringUtils.interpolate(
'<a href="{edx_support_url}">', {
edx_support_url: edxSupportUrl
}
)
),
link_end: HtmlUtils.HTML('</a>')
}
);
}
emailFieldData = {
model: userAccountModel,
title: gettext('Email Address (Sign In)'),
valueAttribute: 'email',
helpMessage: StringUtils.interpolate(
gettext('You receive messages from {platform_name} and course teams at this address.'), // eslint-disable-line max-len
{platform_name: platformName}
),
persistChanges: true
};
if (!allowEmailChange || (syncLearnerProfileData && enterpriseReadonlyAccountFields.fields.indexOf('email') !== -1)) { // eslint-disable-line max-len
emailFieldView = {
view: new AccountSettingsFieldViews.ReadonlyFieldView(emailFieldData)
};
} else {
emailFieldView = {
view: new AccountSettingsFieldViews.EmailFieldView(emailFieldData)
};
}
secondaryEmailFieldData = {
model: userAccountModel,
title: gettext('Recovery Email Address'),
valueAttribute: 'secondary_email',
helpMessage: gettext('You may access your account with this address if single-sign on or access to your primary email is not available.'), // eslint-disable-line max-len
persistChanges: true
};
fullNameFieldData = {
model: userAccountModel,
title: gettext('Full Name'),
valueAttribute: 'name',
helpMessage: gettext('The name that is used for ID verification and that appears on your certificates.'), // eslint-disable-line max-len,
persistChanges: true
};
if (syncLearnerProfileData && enterpriseReadonlyAccountFields.fields.indexOf('name') !== -1) {
fullnameFieldView = {
view: new AccountSettingsFieldViews.ReadonlyFieldView(fullNameFieldData)
};
} else {
fullnameFieldView = {
view: new AccountSettingsFieldViews.TextFieldView(fullNameFieldData)
};
}
countryFieldData = {
model: userAccountModel,
required: true,
title: gettext('Country or Region of Residence'),
valueAttribute: 'country',
options: fieldsData.country.options,
persistChanges: true,
helpMessage: gettext('The country or region where you live.')
};
if (syncLearnerProfileData && enterpriseReadonlyAccountFields.fields.indexOf('country') !== -1) {
countryFieldData.editable = 'never';
countryFieldView = {
view: new AccountSettingsFieldViews.DropdownFieldView(
countryFieldData
)
};
} else {
countryFieldView = {
view: new AccountSettingsFieldViews.DropdownFieldView(countryFieldData)
};
}
levelOfEducationFieldData = fieldsData.level_of_education.options;
if (enableCoppaCompliance) {
levelOfEducationFieldData = levelOfEducationFieldData.filter(option => option[0] !== 'el');
}
aboutSectionsData = [
{
title: gettext('Basic Account Information'),
subtitle: gettext('These settings include basic information about your account.'),
messageType: aboutSectionMessageType,
message: aboutSectionMessage,
fields: [
{
view: new AccountSettingsFieldViews.ReadonlyFieldView({
model: userAccountModel,
title: gettext('Username'),
valueAttribute: 'username',
helpMessage: StringUtils.interpolate(
gettext('The name that identifies you on {platform_name}. You cannot change your username.'), // eslint-disable-line max-len
{platform_name: platformName}
)
})
},
fullnameFieldView,
emailFieldView,
{
view: new AccountSettingsFieldViews.PasswordFieldView({
model: userAccountModel,
title: gettext('Password'),
screenReaderTitle: gettext('Reset Your Password'),
valueAttribute: 'password',
emailAttribute: 'email',
passwordResetSupportUrl: passwordResetSupportUrl,
linkTitle: gettext('Reset Your Password'),
linkHref: fieldsData.password.url,
helpMessage: gettext('Check your email account for instructions to reset your password.') // eslint-disable-line max-len
})
},
{
view: new AccountSettingsFieldViews.LanguagePreferenceFieldView({
model: userPreferencesModel,
title: gettext('Language'),
valueAttribute: 'pref-lang',
required: true,
refreshPageOnSave: true,
helpMessage: StringUtils.interpolate(
gettext('The language used throughout this site. This site is currently available in a limited number of languages. Changing the value of this field will cause the page to refresh.'), // eslint-disable-line max-len
{platform_name: platformName}
),
options: fieldsData.language.options,
persistChanges: true,
focusNextID: '#u-field-select-country'
})
},
countryFieldView,
{
view: new AccountSettingsFieldViews.TimeZoneFieldView({
model: userPreferencesModel,
required: true,
title: gettext('Time Zone'),
valueAttribute: 'time_zone',
helpMessage: gettext('Select the time zone for displaying course dates. If you do not specify a time zone, course dates, including assignment deadlines, will be displayed in your browser\'s local time zone.'), // eslint-disable-line max-len
groupOptions: [{
groupTitle: gettext('All Time Zones'),
selectOptions: fieldsData.time_zone.options,
nullValueOptionLabel: gettext('Default (Local Time Zone)')
}],
persistChanges: true
})
}
]
},
{
title: gettext('Additional Information'),
fields: [
{
view: new AccountSettingsFieldViews.DropdownFieldView({
model: userAccountModel,
title: gettext('Education Completed'),
valueAttribute: 'level_of_education',
options: levelOfEducationFieldData,
persistChanges: true
})
},
{
view: new AccountSettingsFieldViews.DropdownFieldView({
model: userAccountModel,
title: gettext('Gender'),
valueAttribute: 'gender',
options: fieldsData.gender.options,
persistChanges: true
})
},
{
view: new AccountSettingsFieldViews.DropdownFieldView({
model: userAccountModel,
title: gettext('Year of Birth'),
valueAttribute: 'year_of_birth',
options: fieldsData.year_of_birth.options,
persistChanges: true
})
},
{
view: new AccountSettingsFieldViews.LanguageProficienciesFieldView({
model: userAccountModel,
title: gettext('Preferred Language'),
valueAttribute: 'language_proficiencies',
options: fieldsData.preferred_language.options,
persistChanges: true
})
}
]
}
];
if (enableCoppaCompliance) {
yearOfBirthViewIndex = aboutSectionsData[1].fields.findIndex(function(field) {
return field.view.options.valueAttribute === 'year_of_birth';
});
aboutSectionsData[1].fields.splice(yearOfBirthViewIndex, 1);
}
// Secondary email address
if (isSecondaryEmailFeatureEnabled) {
secondaryEmailFieldView = {
view: new AccountSettingsFieldViews.EmailFieldView(secondaryEmailFieldData),
successMessage: function() {
return HtmlUtils.joinHtml(
this.indicators.success,
StringUtils.interpolate(
gettext('We\'ve sent a confirmation message to {new_secondary_email_address}. Click the link in the message to update your secondary email address.'), // eslint-disable-line max-len
{
new_secondary_email_address: this.fieldValue()
}
)
);
}
};
emailFieldViewIndex = aboutSectionsData[0].fields.indexOf(emailFieldView);
// Insert secondary email address after email address field.
aboutSectionsData[0].fields.splice(
emailFieldViewIndex + 1, 0, secondaryEmailFieldView
);
}
// Add the extended profile fields
additionalFields = aboutSectionsData[1];
for (var field in extendedProfileFields) { // eslint-disable-line guard-for-in, no-restricted-syntax, vars-on-top, max-len
fieldItem = extendedProfileFields[field];
if (fieldItem.field_type === 'TextField') {
additionalFields.fields.push({
view: new AccountSettingsFieldViews.ExtendedFieldTextFieldView({
model: userAccountModel,
title: fieldItem.field_label,
fieldName: fieldItem.field_name,
valueAttribute: 'extended_profile',
persistChanges: true
})
});
} else {
if (fieldItem.field_type === 'ListField') {
additionalFields.fields.push({
view: new AccountSettingsFieldViews.ExtendedFieldListFieldView({
model: userAccountModel,
title: fieldItem.field_label,
fieldName: fieldItem.field_name,
options: fieldItem.field_options,
valueAttribute: 'extended_profile',
persistChanges: true
})
});
}
}
}
// Add the social link fields
socialFields = {
title: gettext('Social Media Links'),
subtitle: gettext('Optionally, link your personal accounts to the social media icons on your edX profile.'), // eslint-disable-line max-len
fields: []
};
for (var socialPlatform in socialPlatforms) { // eslint-disable-line guard-for-in, no-restricted-syntax, vars-on-top, max-len
platformData = socialPlatforms[socialPlatform];
socialFields.fields.push(
{
view: new AccountSettingsFieldViews.SocialLinkTextFieldView({
model: userAccountModel,
title: StringUtils.interpolate(
gettext('{platform_display_name} Link'),
{platform_display_name: platformData.display_name}
),
valueAttribute: 'social_links',
helpMessage: StringUtils.interpolate(
gettext('Enter your {platform_display_name} username or the URL to your {platform_display_name} page. Delete the URL to remove the link.'), // eslint-disable-line max-len
{platform_display_name: platformData.display_name}
),
platform: socialPlatform,
persistChanges: true,
placeholder: platformData.example
})
}
);
}
aboutSectionsData.push(socialFields);
// Add account deletion fields
if (displayAccountDeletion) {
accountDeletionFields = {
title: gettext('Delete My Account'),
fields: [],
// Used so content can be rendered external to Backbone
domHookId: 'account-deletion-container'
};
aboutSectionsData.push(accountDeletionFields);
}
// set TimeZoneField to listen to CountryField
getUserField = function(list, search) {
// eslint-disable-next-line no-shadow
return _.find(list, function(field) {
return field.view.options.valueAttribute === search;
}).view;
};
userFields = _.find(aboutSectionsData, function(section) {
return section.title === gettext('Basic Account Information');
}).fields;
timeZoneDropdownField = getUserField(userFields, 'time_zone');
countryDropdownField = getUserField(userFields, 'country');
timeZoneDropdownField.listenToCountryView(countryDropdownField);
accountsSectionData = [
{
title: gettext('Linked Accounts'),
subtitle: StringUtils.interpolate(
gettext('You can link your social media accounts to simplify signing in to {platform_name}.'),
{platform_name: platformName}
),
fields: _.map(authData.providers, function(provider) {
return {
view: new AccountSettingsFieldViews.AuthFieldView({
title: provider.name,
valueAttribute: 'auth-' + provider.id,
helpMessage: '',
connected: provider.connected,
connectUrl: provider.connect_url,
acceptsLogins: provider.accepts_logins,
disconnectUrl: provider.disconnect_url,
platformName: platformName
})
};
})
}
];
ordersHistoryData.unshift(
{
title: gettext('ORDER NAME'),
order_date: gettext('ORDER PLACED'),
price: gettext('TOTAL'),
number: gettext('ORDER NUMBER')
}
);
ordersSectionData = [
{
title: gettext('My Orders'),
subtitle: StringUtils.interpolate(
gettext('This page contains information about orders that you have placed with {platform_name}.'), // eslint-disable-line max-len
{platform_name: platformName}
),
fields: _.map(ordersHistoryData, function(order) {
orderNumber = order.number;
if (orderNumber === 'ORDER NUMBER') {
orderNumber = 'orderId';
}
return {
view: new AccountSettingsFieldViews.OrderHistoryFieldView({
totalPrice: order.price,
orderId: order.number,
orderDate: order.order_date,
receiptUrl: order.receipt_url,
valueAttribute: 'order-' + orderNumber,
lines: order.lines
})
};
})
}
];
accountSettingsView = new AccountSettingsView({
model: userAccountModel,
accountUserId: accountUserId,
el: $accountSettingsElement,
tabSections: {
aboutTabSections: aboutSectionsData,
accountsTabSections: accountsSectionData,
ordersTabSections: ordersSectionData
},
userPreferencesModel: userPreferencesModel,
disableOrderHistoryTab: disableOrderHistoryTab,
betaLanguage: betaLanguage
});
accountSettingsView.render();
focusId = $.cookie('focus_id');
if (focusId) {
// eslint-disable-next-line no-bitwise
if (~focusId.indexOf('beta-language')) {
tabIndex = -1;
// Scroll to top of selected element
$('html, body').animate({
scrollTop: $(focusId).offset().top
}, 'slow');
}
$(focusId).attr({tabindex: tabIndex}).focus();
// Deleting the cookie
document.cookie = 'focus_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/account;';
}
showAccountSettingsPage = function() {
// Record that the account settings page was viewed.
Logger.log('edx.user.settings.viewed', {
page: 'account',
visibility: null,
user_id: accountUserId
});
};
showLoadingError = function() {
accountSettingsView.showLoadingError();
};
userAccountModel.fetch({
success: function() {
// Fetch the user preferences model
userPreferencesModel.fetch({
success: showAccountSettingsPage,
error: showLoadingError
});
},
error: showLoadingError
});
return {
userAccountModel: userAccountModel,
userPreferencesModel: userPreferencesModel,
accountSettingsView: accountSettingsView
};
};
});
}).call(this, define || RequireJS.define);

View File

@@ -1,466 +0,0 @@
// eslint-disable-next-line no-shadow-restricted-names
(function(define, undefined) {
'use strict';
define([
'gettext',
'jquery',
'underscore',
'backbone',
'js/views/fields',
'text!templates/fields/field_text_account.underscore',
'text!templates/fields/field_readonly_account.underscore',
'text!templates/fields/field_link_account.underscore',
'text!templates/fields/field_dropdown_account.underscore',
'text!templates/fields/field_social_link_account.underscore',
'text!templates/fields/field_order_history.underscore',
'edx-ui-toolkit/js/utils/string-utils',
'edx-ui-toolkit/js/utils/html-utils'
], function(
gettext, $, _, Backbone,
FieldViews,
field_text_account_template,
field_readonly_account_template,
field_link_account_template,
field_dropdown_account_template,
field_social_link_template,
field_order_history_template,
StringUtils,
HtmlUtils
) {
var AccountSettingsFieldViews = {
ReadonlyFieldView: FieldViews.ReadonlyFieldView.extend({
fieldTemplate: field_readonly_account_template
}),
TextFieldView: FieldViews.TextFieldView.extend({
fieldTemplate: field_text_account_template
}),
DropdownFieldView: FieldViews.DropdownFieldView.extend({
fieldTemplate: field_dropdown_account_template
}),
EmailFieldView: FieldViews.TextFieldView.extend({
fieldTemplate: field_text_account_template,
successMessage: function() {
return HtmlUtils.joinHtml(
this.indicators.success,
StringUtils.interpolate(
gettext('We\'ve sent a confirmation message to {new_email_address}. Click the link in the message to update your email address.'), // eslint-disable-line max-len
{new_email_address: this.fieldValue()}
)
);
}
}),
LanguagePreferenceFieldView: FieldViews.DropdownFieldView.extend({
fieldTemplate: field_dropdown_account_template,
initialize: function(options) {
this._super(options); // eslint-disable-line no-underscore-dangle
this.listenTo(this.model, 'revertValue', this.revertValue);
},
revertValue: function(event) {
var attributes = {},
oldPrefLang = $(event.target).data('old-lang-code');
if (oldPrefLang) {
attributes['pref-lang'] = oldPrefLang;
this.saveAttributes(attributes);
}
},
saveSucceeded: function() {
var data = {
language: this.modelValue(),
next: window.location.href
};
var view = this;
$.ajax({
type: 'POST',
url: '/i18n/setlang/',
data: data,
dataType: 'html',
success: function() {
view.showSuccessMessage();
},
error: function() {
view.showNotificationMessage(
HtmlUtils.joinHtml(
view.indicators.error,
gettext('You must sign out and sign back in before your language changes take effect.') // eslint-disable-line max-len
)
);
}
});
}
}),
TimeZoneFieldView: FieldViews.DropdownFieldView.extend({
fieldTemplate: field_dropdown_account_template,
initialize: function(options) {
this.options = _.extend({}, options);
_.bindAll(this, 'listenToCountryView', 'updateCountrySubheader', 'replaceOrAddGroupOption');
this._super(options); // eslint-disable-line no-underscore-dangle
},
listenToCountryView: function(view) {
this.listenTo(view.model, 'change:country', this.updateCountrySubheader);
},
updateCountrySubheader: function(user) {
var view = this;
$.ajax({
type: 'GET',
url: '/api/user/v1/preferences/time_zones/',
data: {country_code: user.attributes.country},
success: function(data) {
var countryTimeZones = $.map(data, function(timeZoneInfo) {
return [[timeZoneInfo.time_zone, timeZoneInfo.description]];
});
view.replaceOrAddGroupOption(
'Country Time Zones',
countryTimeZones
);
view.render();
}
});
},
updateValueInField: function() {
var options;
if (this.modelValue()) {
options = [[this.modelValue(), this.displayValue(this.modelValue())]];
this.replaceOrAddGroupOption(
'Currently Selected Time Zone',
options
);
}
this._super(); // eslint-disable-line no-underscore-dangle
},
replaceOrAddGroupOption: function(title, options) {
var groupOption = {
groupTitle: gettext(title),
selectOptions: options
};
var index = _.findIndex(this.options.groupOptions, function(group) {
return group.groupTitle === gettext(title);
});
if (index >= 0) {
this.options.groupOptions[index] = groupOption;
} else {
this.options.groupOptions.unshift(groupOption);
}
}
}),
PasswordFieldView: FieldViews.LinkFieldView.extend({
fieldType: 'button',
fieldTemplate: field_link_account_template,
events: {
'click button': 'linkClicked'
},
initialize: function(options) {
this.options = _.extend({}, options);
this._super(options);
_.bindAll(this, 'resetPassword');
},
linkClicked: function(event) {
event.preventDefault();
this.toggleDisableButton(true);
this.resetPassword(event);
},
resetPassword: function() {
var data = {};
data[this.options.emailAttribute] = this.model.get(this.options.emailAttribute);
var view = this;
$.ajax({
type: 'POST',
url: view.options.linkHref,
data: data,
success: function() {
view.showSuccessMessage();
view.setMessageTimeout();
},
error: function(xhr) {
view.showErrorMessage(xhr);
view.setMessageTimeout();
view.toggleDisableButton(false);
}
});
},
toggleDisableButton: function(disabled) {
var button = this.$('#u-field-link-' + this.options.valueAttribute);
if (button) {
button.prop('disabled', disabled);
}
},
setMessageTimeout: function() {
var view = this;
setTimeout(function() {
view.showHelpMessage();
}, 6000);
},
successMessage: function() {
return HtmlUtils.joinHtml(
this.indicators.success,
HtmlUtils.interpolateHtml(
gettext('We\'ve sent a message to {email}. Click the link in the message to reset your password. Didn\'t receive the message? Contact {anchorStart}technical support{anchorEnd}.'), // eslint-disable-line max-len
{
email: this.model.get(this.options.emailAttribute),
anchorStart: HtmlUtils.HTML(
StringUtils.interpolate(
'<a href="{passwordResetSupportUrl}">', {
passwordResetSupportUrl: this.options.passwordResetSupportUrl
}
)
),
anchorEnd: HtmlUtils.HTML('</a>')
}
)
);
}
}),
LanguageProficienciesFieldView: FieldViews.DropdownFieldView.extend({
fieldTemplate: field_dropdown_account_template,
modelValue: function() {
var modelValue = this.model.get(this.options.valueAttribute);
if (_.isArray(modelValue) && modelValue.length > 0) {
return modelValue[0].code;
} else {
return null;
}
},
saveValue: function() {
var attributes = {},
value = '';
if (this.persistChanges === true) {
value = this.fieldValue() ? [{code: this.fieldValue()}] : [];
attributes[this.options.valueAttribute] = value;
this.saveAttributes(attributes);
}
}
}),
SocialLinkTextFieldView: FieldViews.TextFieldView.extend({
render: function() {
HtmlUtils.setHtml(this.$el, HtmlUtils.template(field_text_account_template)({
id: this.options.valueAttribute + '_' + this.options.platform,
title: this.options.title,
value: this.modelValue(),
message: this.options.helpMessage,
placeholder: this.options.placeholder || ''
}));
this.delegateEvents();
return this;
},
modelValue: function() {
var socialLinks = this.model.get(this.options.valueAttribute);
for (var i = 0; i < socialLinks.length; i++) { // eslint-disable-line vars-on-top
if (socialLinks[i].platform === this.options.platform) {
return socialLinks[i].social_link;
}
}
return null;
},
saveValue: function() {
var attributes, value;
if (this.persistChanges === true) {
attributes = {};
value = this.fieldValue() != null ? [{
platform: this.options.platform,
social_link: this.fieldValue()
}] : [];
attributes[this.options.valueAttribute] = value;
this.saveAttributes(attributes);
}
}
}),
ExtendedFieldTextFieldView: FieldViews.TextFieldView.extend({
render: function() {
HtmlUtils.setHtml(this.$el, HtmlUtils.template(field_text_account_template)({
id: this.options.valueAttribute + '_' + this.options.field_name,
title: this.options.title,
value: this.modelValue(),
message: this.options.helpMessage,
placeholder: this.options.placeholder || ''
}));
this.delegateEvents();
return this;
},
modelValue: function() {
var extendedProfileFields = this.model.get(this.options.valueAttribute);
for (var i = 0; i < extendedProfileFields.length; i++) { // eslint-disable-line vars-on-top
if (extendedProfileFields[i].field_name === this.options.fieldName) {
return extendedProfileFields[i].field_value;
}
}
return null;
},
saveValue: function() {
var attributes, value;
if (this.persistChanges === true) {
attributes = {};
value = this.fieldValue() != null ? [{
field_name: this.options.fieldName,
field_value: this.fieldValue()
}] : [];
attributes[this.options.valueAttribute] = value;
this.saveAttributes(attributes);
}
}
}),
ExtendedFieldListFieldView: FieldViews.DropdownFieldView.extend({
fieldTemplate: field_dropdown_account_template,
modelValue: function() {
var extendedProfileFields = this.model.get(this.options.valueAttribute);
for (var i = 0; i < extendedProfileFields.length; i++) { // eslint-disable-line vars-on-top
if (extendedProfileFields[i].field_name === this.options.fieldName) {
return extendedProfileFields[i].field_value;
}
}
return null;
},
saveValue: function() {
var attributes = {},
value;
if (this.persistChanges === true) {
value = this.fieldValue() ? [{
field_name: this.options.fieldName,
field_value: this.fieldValue()
}] : [];
attributes[this.options.valueAttribute] = value;
this.saveAttributes(attributes);
}
}
}),
AuthFieldView: FieldViews.LinkFieldView.extend({
fieldTemplate: field_social_link_template,
className: function() {
return 'u-field u-field-social u-field-' + this.options.valueAttribute;
},
initialize: function(options) {
this.options = _.extend({}, options);
this._super(options);
_.bindAll(this, 'redirect_to', 'disconnect', 'successMessage', 'inProgressMessage');
},
render: function() {
var linkTitle = '',
linkClass = '',
subTitle = '',
screenReaderTitle = StringUtils.interpolate(
gettext('Link your {accountName} account'),
{accountName: this.options.title}
);
if (this.options.connected) {
linkTitle = gettext('Unlink This Account');
linkClass = 'social-field-linked';
subTitle = StringUtils.interpolate(
gettext('You can use your {accountName} account to sign in to your {platformName} account.'), // eslint-disable-line max-len
{accountName: this.options.title, platformName: this.options.platformName}
);
screenReaderTitle = StringUtils.interpolate(
gettext('Unlink your {accountName} account'),
{accountName: this.options.title}
);
} else if (this.options.acceptsLogins) {
linkTitle = gettext('Link Your Account');
linkClass = 'social-field-unlinked';
subTitle = StringUtils.interpolate(
gettext('Link your {accountName} account to your {platformName} account and use {accountName} to sign in to {platformName}.'), // eslint-disable-line max-len
{accountName: this.options.title, platformName: this.options.platformName}
);
}
HtmlUtils.setHtml(this.$el, HtmlUtils.template(this.fieldTemplate)({
id: this.options.valueAttribute,
title: this.options.title,
screenReaderTitle: screenReaderTitle,
linkTitle: linkTitle,
subTitle: subTitle,
linkClass: linkClass,
linkHref: '#',
message: this.helpMessage
}));
this.delegateEvents();
return this;
},
linkClicked: function(event) {
event.preventDefault();
this.showInProgressMessage();
if (this.options.connected) {
this.disconnect();
} else {
// Direct the user to the providers site to start the authentication process.
// See python-social-auth docs for more information.
this.redirect_to(this.options.connectUrl);
}
},
redirect_to: function(url) {
window.location.href = url;
},
disconnect: function() {
var data = {};
// Disconnects the provider from the user's edX account.
// See python-social-auth docs for more information.
var view = this;
$.ajax({
type: 'POST',
url: this.options.disconnectUrl,
data: data,
dataType: 'html',
success: function() {
view.options.connected = false;
view.render();
view.showSuccessMessage();
},
error: function(xhr) {
view.showErrorMessage(xhr);
}
});
},
inProgressMessage: function() {
return HtmlUtils.joinHtml(this.indicators.inProgress, (
this.options.connected ? gettext('Unlinking') : gettext('Linking')
));
},
successMessage: function() {
return HtmlUtils.joinHtml(this.indicators.success, gettext('Successfully unlinked.'));
}
}),
OrderHistoryFieldView: FieldViews.ReadonlyFieldView.extend({
fieldType: 'orderHistory',
fieldTemplate: field_order_history_template,
initialize: function(options) {
this.options = options;
this._super(options);
this.template = HtmlUtils.template(this.fieldTemplate);
},
render: function() {
HtmlUtils.setHtml(this.$el, this.template({
totalPrice: this.options.totalPrice,
orderId: this.options.orderId,
orderDate: this.options.orderDate,
receiptUrl: this.options.receiptUrl,
valueAttribute: this.options.valueAttribute,
lines: this.options.lines
}));
this.delegateEvents();
return this;
}
})
};
return AccountSettingsFieldViews;
});
}).call(this, define || RequireJS.define);

View File

@@ -1,157 +0,0 @@
// eslint-disable-next-line no-shadow-restricted-names
(function(define, undefined) {
'use strict';
define([
'gettext',
'jquery',
'underscore',
'common/js/components/views/tabbed_view',
'edx-ui-toolkit/js/utils/html-utils',
'js/student_account/views/account_section_view',
'text!templates/student_account/account_settings.underscore'
], function(gettext, $, _, TabbedView, HtmlUtils, AccountSectionView, accountSettingsTemplate) {
var AccountSettingsView = TabbedView.extend({
navLink: '.account-nav-link',
activeTab: 'aboutTabSections',
events: {
'click .account-nav-link': 'switchTab',
'keydown .account-nav-link': 'keydownHandler',
'click .btn-alert-primary': 'revertValue'
},
initialize: function(options) {
this.options = options;
_.bindAll(this, 'render', 'switchTab', 'setActiveTab', 'showLoadingError');
},
render: function() {
var tabName, betaLangMessage, helpTranslateText, helpTranslateLink, betaLangCode, oldLangCode,
view = this;
var accountSettingsTabs = [
{
name: 'aboutTabSections',
id: 'about-tab',
label: gettext('Account Information'),
class: 'active',
tabindex: 0,
selected: true,
expanded: true
},
{
name: 'accountsTabSections',
id: 'accounts-tab',
label: gettext('Linked Accounts'),
tabindex: -1,
selected: false,
expanded: false
}
];
if (!view.options.disableOrderHistoryTab) {
accountSettingsTabs.push({
name: 'ordersTabSections',
id: 'orders-tab',
label: gettext('Order History'),
tabindex: -1,
selected: false,
expanded: false
});
}
if (!_.isEmpty(view.options.betaLanguage) && $.cookie('old-pref-lang')) {
betaLangMessage = HtmlUtils.interpolateHtml(
gettext('You have set your language to {beta_language}, which is currently not fully translated. You can help us translate this language fully by joining the Transifex community and adding translations from English for learners that speak {beta_language}.'), // eslint-disable-line max-len
{
beta_language: view.options.betaLanguage.name
}
);
helpTranslateText = HtmlUtils.interpolateHtml(
gettext('Help Translate into {beta_language}'),
{
beta_language: view.options.betaLanguage.name
}
);
betaLangCode = this.options.betaLanguage.code.split('-');
if (betaLangCode.length > 1) {
betaLangCode = betaLangCode[0] + '_' + betaLangCode[1].toUpperCase();
} else {
betaLangCode = betaLangCode[0];
}
helpTranslateLink = 'https://www.transifex.com/open-edx/edx-platform/translate/#' + betaLangCode;
oldLangCode = $.cookie('old-pref-lang');
// Deleting the cookie
document.cookie = 'old-pref-lang=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/account;';
$.cookie('focus_id', '#beta-language-message');
}
HtmlUtils.setHtml(this.$el, HtmlUtils.template(accountSettingsTemplate)({
accountSettingsTabs: accountSettingsTabs,
HtmlUtils: HtmlUtils,
message: betaLangMessage,
helpTranslateText: helpTranslateText,
helpTranslateLink: helpTranslateLink,
oldLangCode: oldLangCode
}));
_.each(accountSettingsTabs, function(tab) {
tabName = tab.name;
view.renderSection(view.options.tabSections[tabName], tabName, tab.label);
});
return this;
},
switchTab: function(e) {
var $currentTab,
$accountNavLink = $('.account-nav-link');
if (e) {
e.preventDefault();
$currentTab = $(e.target);
this.activeTab = $currentTab.data('name');
_.each(this.$('.account-settings-tabpanels'), function(tabPanel) {
$(tabPanel).addClass('hidden');
});
$('#' + this.activeTab + '-tabpanel').removeClass('hidden');
$accountNavLink.attr('tabindex', -1);
$accountNavLink.attr('aria-selected', false);
$accountNavLink.attr('aria-expanded', false);
$currentTab.attr('tabindex', 0);
$currentTab.attr('aria-selected', true);
$currentTab.attr('aria-expanded', true);
$(this.navLink).removeClass('active');
$currentTab.addClass('active');
}
},
setActiveTab: function() {
this.switchTab();
},
renderSection: function(tabSections, tabName, tabLabel) {
var accountSectionView = new AccountSectionView({
tabName: tabName,
tabLabel: tabLabel,
sections: tabSections,
el: '#' + tabName + '-tabpanel'
});
accountSectionView.render();
},
showLoadingError: function() {
this.$('.ui-loading-error').removeClass('is-hidden');
},
revertValue: function(event) {
this.options.userPreferencesModel.trigger('revertValue', event);
}
});
return AccountSettingsView;
});
}).call(this, define || RequireJS.define);