Compare commits

..

4 Commits

Author SHA1 Message Date
Kyle McCormick
6f0e6b4c82 Update .env.development for devstack 2020-04-06 08:19:52 -04:00
Kyle McCormick
48c7204e04 npm install 2020-04-05 17:35:01 -04:00
Kyle McCormick
2b93e5fab0 Use kdmccormick's frontend-build; add dev-build command 2020-04-05 17:35:01 -04:00
Kyle McCormick
13c5b12500 Make React routes relative 2020-04-05 17:23:42 -04:00
30 changed files with 6369 additions and 3301 deletions

View File

@@ -1,20 +1,20 @@
ACCESS_TOKEN_COOKIE_NAME='edx-jwt-cookie-header-payload'
BASE_URL='localhost:1997'
BASE_URL='localhost:19000/account/'
CREDENTIALS_BASE_URL='http://localhost:18150'
CSRF_TOKEN_API_PATH='/csrf/api/v1/token'
ECOMMERCE_BASE_URL='http://localhost:18130'
LANGUAGE_PREFERENCE_COOKIE_NAME='openedx-language-preference'
LMS_BASE_URL='http://localhost:18000'
LOGIN_URL='http://localhost:18000/login'
LOGOUT_URL='http://localhost:18000/logout'
LOGOUT_URL='http://localhost:18000/login'
MARKETING_SITE_BASE_URL='http://localhost:18000'
NODE_ENV='development'
ORDER_HISTORY_URL='localhost:1996/orders'
PORT=1997
ORDER_HISTORY_URL='localhost:19000/orders/'
PORT=1997 # For standalone dev server only.
REFRESH_ACCESS_TOKEN_ENDPOINT='http://localhost:18000/login_refresh'
SEGMENT_KEY=null
SITE_NAME='edX'
SUPPORT_URL='http://localhost:18000/support'
USER_INFO_COOKIE_NAME='edx-user-info'
# Temporary, Remove this once we are ready to release the feature.
COACHING_ENABLED=true
COACHING_ENABLED=''

View File

@@ -6,7 +6,7 @@ ECOMMERCE_BASE_URL='http://localhost:18130'
LANGUAGE_PREFERENCE_COOKIE_NAME='openedx-language-preference'
LMS_BASE_URL='http://localhost:18000'
LOGIN_URL='http://localhost:18000/login'
LOGOUT_URL='http://localhost:18000/logout'
LOGOUT_URL='http://localhost:18000/login'
MARKETING_SITE_BASE_URL='http://localhost:18000'
NODE_ENV=null
ORDER_HISTORY_URL='localhost:1996/orders'

9131
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,7 @@
},
"scripts": {
"build": "fedx-scripts webpack",
"dev-build": "fedx-scripts webpack-dev",
"i18n_extract": "BABEL_ENV=i18n fedx-scripts babel src --quiet > /dev/null",
"is-es5": "es-check es5 ./dist/*.js",
"lint": "fedx-scripts eslint",
@@ -73,7 +74,7 @@
"universal-cookie": "4.0.3"
},
"devDependencies": {
"@edx/frontend-build": "2.0.6",
"@edx/frontend-build": "github:kdmccormick/frontend-build#kdmccormick/devstack",
"codecov": "3.6.5",
"enzyme": "3.10.0",
"enzyme-adapter-react-16": "1.15.2",

View File

@@ -31,8 +31,6 @@ import {
YEAR_OF_BIRTH_OPTIONS,
EDUCATION_LEVELS,
GENDER_OPTIONS,
COUNTRY_WITH_STATES,
getStatesList,
} from './data/constants';
import { fetchSiteLanguages } from './site-language';
import CoachingToggle from './coaching/CoachingToggle';
@@ -84,15 +82,11 @@ class AccountSettingsPage extends React.Component {
return concatTimeZoneOptions;
});
getLocalizedOptions = memoize((locale, country) => ({
getLocalizedOptions = memoize(locale => ({
countryOptions: [{
value: '',
label: this.props.intl.formatMessage(messages['account.settings.field.country.options.empty']),
}].concat(getCountryList(locale).map(({ code, name }) => ({ value: code, label: name }))),
stateOptions: [{
value: '',
label: this.props.intl.formatMessage(messages['account.settings.field.state.options.empty']),
}].concat(getStatesList(country)),
languageProficiencyOptions: [{
value: '',
label: this.props.intl.formatMessage(messages['account.settings.field.language_proficiencies.options.empty']),
@@ -190,7 +184,7 @@ class AccountSettingsPage extends React.Component {
}
renderSecondaryEmailField(editableFieldProps) {
if (!Boolean(this.props.formValues.secondary_email_enabled)) {
if (this.props.hiddenFields.includes('secondary_email')) {
return null;
}
@@ -215,15 +209,11 @@ class AccountSettingsPage extends React.Component {
// Memoized options lists
const {
countryOptions,
stateOptions,
languageProficiencyOptions,
yearOfBirthOptions,
educationLevelOptions,
genderOptions,
} = this.getLocalizedOptions(this.context.locale, this.props.formValues.country);
// Show State field only if the country is US (could include Canada later)
const showState = this.props.formValues.country == COUNTRY_WITH_STATES;
} = this.getLocalizedOptions(this.context.locale);
const timeZoneOptions = this.getLocalizedTimeZoneOptions(
this.props.timeZoneOptions,
@@ -304,22 +294,6 @@ class AccountSettingsPage extends React.Component {
isEditable={this.isEditable('country')}
{...editableFieldProps}
/>
{showState &&
<EditableField
name="state"
type="select"
value={this.props.formValues.state}
options={stateOptions}
label={this.props.intl.formatMessage(messages['account.settings.field.state'])}
emptyLabel={
this.isEditable('state') ?
this.props.intl.formatMessage(messages['account.settings.field.state.empty']) :
this.renderEmptyStaticFieldMessage()
}
isEditable={this.isEditable('state')}
{...editableFieldProps}
/>
}
</div>
<div className="account-section" id="profile-information">
@@ -514,11 +488,11 @@ AccountSettingsPage.propTypes = {
social_link_facebook: PropTypes.string,
social_link_twitter: PropTypes.string,
time_zone: PropTypes.string,
coaching: PropTypes.shape({
coaching_consent: PropTypes.bool.isRequired,
coaching: PropTypes.objectOf(PropTypes.shape({
coaching_consent: PropTypes.string.isRequired,
user: PropTypes.number.isRequired,
eligible_for_coaching: PropTypes.bool.isRequired,
}),
})),
}).isRequired,
siteLanguage: PropTypes.shape({
previousValue: PropTypes.string,
@@ -530,8 +504,8 @@ AccountSettingsPage.propTypes = {
})),
profileDataManager: PropTypes.string,
staticFields: PropTypes.arrayOf(PropTypes.string),
hiddenFields: PropTypes.arrayOf(PropTypes.string),
isActive: PropTypes.bool,
secondary_email_enabled: PropTypes.bool,
timeZoneOptions: PropTypes.arrayOf(PropTypes.shape({
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
@@ -558,9 +532,9 @@ AccountSettingsPage.defaultProps = {
countryTimeZoneOptions: [],
profileDataManager: null,
staticFields: [],
hiddenFields: ['secondary_email'],
tpaProviders: [],
isActive: true,
secondary_email_enabled: false,
};
export default connect(accountSettingsPageSelector, {

View File

@@ -156,21 +156,6 @@ const messages = defineMessages({
defaultMessage: 'Select a Country',
description: 'Option for empty value on account settings country field.',
},
'account.settings.field.state': {
id: 'account.settings.field.state',
defaultMessage: 'State',
description: 'Label for account settings state field.',
},
'account.settings.field.state.empty': {
id: 'account.settings.field.state.empty',
defaultMessage: 'Add state',
description: 'Placeholder for empty account settings state field.',
},
'account.settings.field.state.options.empty': {
id: 'account.settings.field.state.options.empty',
defaultMessage: 'Select a State',
description: 'Option for empty value on account settings state field.',
},
'account.settings.field.site.language': {
id: 'account.settings.field.site.language',
defaultMessage: 'Site language',

View File

@@ -12,7 +12,7 @@ import PageLoading from '../PageLoading';
import CoachingConsentForm from './CoachingConsentForm';
import messages from './CoachingConsent.messages';
import LogoSVG from '../../logo.svg';
import { fetchSettings, saveSettings, saveMultipleSettings } from '../data/actions';
import { fetchSettings, saveSettings } from '../data/actions';
import { coachingConsentPageSelector } from '../data/selectors';
const Logo = ({ src, alt, ...attributes }) => (
@@ -96,7 +96,9 @@ class CoachingConsent extends React.Component {
// Check if all values from the form have confirmation values
if (
this.state.formSubmitted &&
this.props.saveState === 'complete'
this.props.confirmationValues.coaching &&
this.props.confirmationValues.name &&
this.props.confirmationValues.phone_number
) {
allSubmissionsComplete = true;
}
@@ -123,39 +125,21 @@ class CoachingConsent extends React.Component {
this.setState({
formErrors: {},
formSubmitted: true,
declineSubmitted: false,
});
// Must store target values or they disappear before the async function can use them.
const fullName = e.target.fullName.value;
const phoneNumber = e.target.phoneNumber.value;
const coachingValues = this.props.formValues.coaching;
// !important: The order of this data matters!
// The order that this data is in, is the order that the saveSettings() function
// is called.
const settingsSubmissions = [];
if (!this.props.profileDataManager) {
settingsSubmissions.push({
formId: 'name',
commitValues: fullName,
});
}
Array.prototype.push.apply(settingsSubmissions, [
{
formId: 'coaching',
commitValues: {
...coachingValues,
phone_number: phoneNumber,
coaching_consent: true,
consent_form_seen: true,
},
},
{
formId: 'phone_number',
commitValues: phoneNumber,
},
]);
this.props.saveMultipleSettings(settingsSubmissions);
// These will overwrite each other's redux states (see componentDidUpdate note)
this.props.saveSettings('name', fullName);
this.props.saveSettings('phone_number', phoneNumber);
this.props.saveSettings('coaching', {
...coachingValues,
phone_number: phoneNumber,
coaching_consent: true,
consent_form_seen: true,
});
}
async declineCoaching(e) {
@@ -163,7 +147,6 @@ class CoachingConsent extends React.Component {
this.setState({
formErrors: {},
declineSubmitted: true,
formSubmitted: false,
});
// Must store target values or they disappear before the async function can use them.
const coachingValues = this.props.formValues.coaching;
@@ -185,7 +168,6 @@ class CoachingConsent extends React.Component {
formErrors={this.state.formErrors}
formValues={this.props.formValues}
redirectUrl={this.state.redirectUrl}
profileDataManager={this.props.profileDataManager}
/>);
case VIEWS.SUCCESS_PENDING:
return <PageLoading srMessage="Submitting..." />;
@@ -209,6 +191,7 @@ class CoachingConsent extends React.Component {
const { loaded } = this.props;
const formHasErrors = Object.keys(this.state.formErrors).length > 0;
let currentView = null;
// This amount of logic was making the template very hard to read, so I broke it out into views.
if (!loaded) {
currentView = VIEWS.NOT_LOADED;
@@ -277,8 +260,6 @@ AutoRedirect.propTypes = {
CoachingConsent.defaultProps = {
loaded: false,
saveState: undefined,
profileDataManager: null,
};
CoachingConsent.propTypes = {
@@ -304,13 +285,9 @@ CoachingConsent.propTypes = {
}).isRequired,
fetchSettings: PropTypes.func.isRequired,
saveSettings: PropTypes.func.isRequired,
saveMultipleSettings: PropTypes.func.isRequired,
saveState: PropTypes.string,
profileDataManager: PropTypes.string,
};
export default connect(coachingConsentPageSelector, {
fetchSettings,
saveSettings,
saveMultipleSettings,
})(injectIntl(CoachingConsent));

View File

@@ -56,11 +56,6 @@ const messages = defineMessages({
defaultMessage: 'Start my course',
description: 'Text that the user will be sent back to the courseware',
},
'account.settings.coaching.managed.support': {
id: 'account.settings.coaching.managed.support',
defaultMessage: 'support',
description: 'website support',
},
});
export default messages;

View File

@@ -1,30 +1,15 @@
import React from 'react';
import { getConfig } from '@edx/frontend-platform';
import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-platform/i18n';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Input, Button, Hyperlink } from '@edx/paragon';
import PropTypes from 'prop-types';
import Alert from '../Alert';
import messages from './CoachingConsent.messages';
const ErrorMessage = props => (
<div className="alert-warning mb-2">{props.message}</div>
);
const ManagedProfileAlert = ({ profileDataManager }) => (
<Alert className="alert alert-primary" role="alert">
<FormattedMessage
id="account.settings.coaching.managed.alert"
defaultMessage="Your name is managed by {managerTitle}. Contact your administrator for help."
description="alert message informing the user their account data is managed by a third party"
values={{
managerTitle: <b>{profileDataManager}</b>,
}}
/>
</Alert>
);
const CoachingForm = props => (
<div className="col-12 col-md-6 col-xl-5 mx-auto mt-4 p-5 shadow-lg">
<h2 className="h2">
@@ -34,17 +19,12 @@ const CoachingForm = props => (
<div>
<form onSubmit={props.onSubmit}>
<div className="py-3">
{
!!props.profileDataManager &&
<ManagedProfileAlert profileDataManager={props.profileDataManager} />
}
<ErrorMessage message={props.formErrors.name} />
<label className="h6" htmlFor="fullName">{props.intl.formatMessage(messages['account.settings.coaching.consent.label.name'])}</label>
<Input
type="text"
name="full-name"
id="fullName"
disabled={!!props.profileDataManager}
defaultValue={props.formValues.name}
/>
</div>
@@ -111,7 +91,6 @@ CoachingForm.propTypes = {
phone_number: PropTypes.string,
}),
redirectUrl: PropTypes.string.isRequired,
profileDataManager: PropTypes.string.isRequired,
};
ErrorMessage.defaultProps = {
@@ -122,9 +101,4 @@ ErrorMessage.propTypes = {
message: PropTypes.string,
};
ManagedProfileAlert.propTypes = {
profileDataManager: PropTypes.string.isRequired,
intl: intlShape.isRequired,
};
export default injectIntl(CoachingForm);

View File

@@ -5,7 +5,7 @@ import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { ValidationFormGroup, Input } from '@edx/paragon';
import messages from './CoachingToggle.messages';
import { editableFieldSelector } from '../data/selectors';
import { saveSettings, updateDraft, saveMultipleSettings } from '../data/actions';
import { saveSettings, updateDraft } from '../data/actions';
import EditableField from '../EditableField';
@@ -18,25 +18,7 @@ const CoachingToggle = props => (
label={props.intl.formatMessage(messages['account.settings.field.phone_number'])}
emptyLabel={props.intl.formatMessage(messages['account.settings.field.phone_number.empty'])}
onChange={props.updateDraft}
onSubmit={() => {
const { coaching } = props;
if (coaching.coaching_consent === true) {
return props.saveMultipleSettings([
{
formId: 'coaching',
commitValues: {
...coaching,
phone_number: props.phone_number,
},
},
{
formId: 'phone_number',
commitValues: props.phone_number,
},
]);
}
return props.saveSettings('phone_number', props.phone_number);
}}
onSubmit={props.saveSettings}
/>
<ValidationFormGroup
for="coachingConsent"
@@ -55,11 +37,9 @@ const CoachingToggle = props => (
value={props.coaching.coaching_consent}
onChange={async (e) => {
const { name } = e.target;
// eslint-disable-next-line camelcase
const { user, eligible_for_coaching } = props.coaching;
const value = {
user,
eligible_for_coaching,
...props.coaching,
phone_number: props.phone_number,
coaching_consent: e.target.checked,
};
props.saveSettings(name, value);
@@ -73,20 +53,18 @@ const CoachingToggle = props => (
CoachingToggle.defaultProps = {
phone_number: '',
error: '',
saveState: undefined,
};
CoachingToggle.propTypes = {
name: PropTypes.string.isRequired,
error: PropTypes.string,
coaching: PropTypes.shape({
coaching_consent: PropTypes.bool.isRequired,
coaching: PropTypes.objectOf(PropTypes.shape({
coaching_consent: PropTypes.string.isRequired,
user: PropTypes.number.isRequired,
eligible_for_coaching: PropTypes.bool.isRequired,
}).isRequired,
saveState: PropTypes.oneOf(['default', 'pending', 'complete', 'error']),
})).isRequired,
saveState: PropTypes.func.isRequired,
saveSettings: PropTypes.func.isRequired,
saveMultipleSettings: PropTypes.func.isRequired,
updateDraft: PropTypes.func.isRequired,
intl: intlShape.isRequired,
phone_number: PropTypes.string,
@@ -95,5 +73,4 @@ CoachingToggle.propTypes = {
export default connect(editableFieldSelector, {
saveSettings,
updateDraft,
saveMultipleSettings,
})(injectIntl(CoachingToggle));

View File

@@ -18,7 +18,7 @@ const messages = defineMessages({
},
'account.settings.field.coaching_consent.tooltip': {
id: 'account.settings.field.coaching_consent.tooltip',
defaultMessage: 'MicroBachelors programs include text message based coaching that helps you pair educational experiences with your career goals through one-on-one advice. Coaching services are included at no additional cost, and are available to learners with U.S. mobile phone numbers. Standard messaging rates apply. Text STOP at anytime to opt-out of messages.',
defaultMessage: 'MicroBachelors programs include text message based coaching that helps you pair educational experiences with your career goals through one-on-one advice. Coaching services are included at no additional cost, and are available in English and Spanish languages. Standard messaging rates apply. Text STOP at anytime to opt-out of messages.',
description: 'A tooltip explaining what coaching is and who it is for',
},
'account.settings.field.coaching_consent.error': {

View File

@@ -1,6 +1,5 @@
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { getConfig } from '@edx/frontend-platform';
import get from 'lodash.get';
/**
* get all settings related to the coaching plugin. Settings used
@@ -8,20 +7,21 @@ import get from 'lodash.get';
* @param {Number} userId users are identified in the api by LMS id
*/
export async function getCoachingPreferences(userId) {
let data = {};
let data = null;
try {
({ data } = await getAuthenticatedHttpClient()
.get(`${getConfig().LMS_BASE_URL}/api/coaching/v1/users/${userId}/`));
} catch (error) {
// If a user isn't active the API call will fail with a lack of credentials.
// Default values so the client doesn't fail if the user doesn't have an entry in the
// UserCoaching model yet, with the assumption that they'll be eligible for coaching
// when they hit this form.
data = {
coaching_consent: false,
user: userId,
eligible_for_coaching: false,
eligible_for_coaching: true,
consent_form_seen: false,
};
}
return data;
}
@@ -40,11 +40,9 @@ export async function patchCoachingPreferences(userId, commitValues) {
.catch((error) => {
const apiError = Object.create(error);
apiError.fieldErrors = JSON.parse(error.customAttributes.httpErrorResponseData);
if (get(apiError, 'fieldErrors.phone_number')) {
// eslint-disable-next-line prefer-destructuring
apiError.fieldErrors.coaching = apiError.fieldErrors.phone_number[0];
delete apiError.fieldErrors.phone_number;
}
// eslint-disable-next-line prefer-destructuring
apiError.fieldErrors.coaching = apiError.fieldErrors.phone_number[0];
delete apiError.fieldErrors.phone_number;
throw apiError;
});
return commitValues;

View File

@@ -2,7 +2,6 @@ import { AsyncActionType } from './utils';
export const FETCH_SETTINGS = new AsyncActionType('ACCOUNT_SETTINGS', 'FETCH_SETTINGS');
export const SAVE_SETTINGS = new AsyncActionType('ACCOUNT_SETTINGS', 'SAVE_SETTINGS');
export const SAVE_MULTIPLE_SETTINGS = new AsyncActionType('ACCOUNT_SETTINGS', 'SAVE_MULTIPLE_SETTINGS');
export const FETCH_TIME_ZONES = new AsyncActionType('ACCOUNT_SETTINGS', 'FETCH_TIME_ZONES');
export const SAVE_PREVIOUS_SITE_LANGUAGE = 'SAVE_PREVIOUS_SITE_LANGUAGE';
export const OPEN_FORM = 'OPEN_FORM';
@@ -100,25 +99,6 @@ export const savePreviousSiteLanguage = previousSiteLanguage => ({
payload: { previousSiteLanguage },
});
export const saveMultipleSettings = settingsArray => ({
type: SAVE_MULTIPLE_SETTINGS.BASE,
payload: { settingsArray },
});
export const saveMultipleSettingsBegin = () => ({
type: SAVE_MULTIPLE_SETTINGS.BEGIN,
});
export const saveMultipleSettingsSuccess = settingsArray => ({
type: SAVE_MULTIPLE_SETTINGS.SUCCESS,
payload: { settingsArray },
});
export const saveMultipleSettingsFailure = ({ fieldErrors, message }) => ({
type: SAVE_MULTIPLE_SETTINGS.FAILURE,
payload: { errors: fieldErrors, message },
});
// FETCH TIME_ZONE ACTIONS
export const fetchTimeZones = country => ({

View File

@@ -31,84 +31,4 @@ export const GENDER_OPTIONS = [
'o',
];
export const COUNTRY_WITH_STATES = 'US';
export const TRANSIFEX_LANGUAGE_BASE_URL = 'https://www.transifex.com/open-edx/edx-platform/language/';
const COUNTRY_STATES_MAP = {
CA: [
{ value: 'AB', label: 'Alberta' },
{ value: 'BC', label: 'British Columbia' },
{ value: 'MB', label: 'Manitoba' },
{ value: 'NB', label: 'New Brunswick' },
{ value: 'NL', label: 'Newfoundland and Labrador' },
{ value: 'NS', label: 'Nova Scotia' },
{ value: 'NT', label: 'Northwest Territories' },
{ value: 'NU', label: 'Nunavut' },
{ value: 'ON', label: 'Ontario' },
{ value: 'PE', label: 'Prince Edward Island' },
{ value: 'QC', label: 'Québec' },
{ value: 'SK', label: 'Saskatchewan' },
{ value: 'YT', label: 'Yukon' },
],
US: [
{ value: 'AL', label: 'Alabama' },
{ value: 'AK', label: 'Alaska' },
{ value: 'AZ', label: 'Arizona' },
{ value: 'AR', label: 'Arkansas' },
{ value: 'AA', label: 'Armed Forces Americas' },
{ value: 'AE', label: 'Armed Forces Europe' },
{ value: 'AP', label: 'Armed Forces Pacific' },
{ value: 'CA', label: 'California' },
{ value: 'CO', label: 'Colorado' },
{ value: 'CT', label: 'Connecticut' },
{ value: 'DE', label: 'Delaware' },
{ value: 'DC', label: 'District Of Columbia' },
{ value: 'FL', label: 'Florida' },
{ value: 'GA', label: 'Georgia' },
{ value: 'HI', label: 'Hawaii' },
{ value: 'ID', label: 'Idaho' },
{ value: 'IL', label: 'Illinois' },
{ value: 'IN', label: 'Indiana' },
{ value: 'IA', label: 'Iowa' },
{ value: 'KS', label: 'Kansas' },
{ value: 'KY', label: 'Kentucky' },
{ value: 'LA', label: 'Louisiana' },
{ value: 'ME', label: 'Maine' },
{ value: 'MD', label: 'Maryland' },
{ value: 'MA', label: 'Massachusetts' },
{ value: 'MI', label: 'Michigan' },
{ value: 'MN', label: 'Minnesota' },
{ value: 'MS', label: 'Mississippi' },
{ value: 'MO', label: 'Missouri' },
{ value: 'MT', label: 'Montana' },
{ value: 'NE', label: 'Nebraska' },
{ value: 'NV', label: 'Nevada' },
{ value: 'NH', label: 'New Hampshire' },
{ value: 'NJ', label: 'New Jersey' },
{ value: 'NM', label: 'New Mexico' },
{ value: 'NY', label: 'New York' },
{ value: 'NC', label: 'North Carolina' },
{ value: 'ND', label: 'North Dakota' },
{ value: 'OH', label: 'Ohio' },
{ value: 'OK', label: 'Oklahoma' },
{ value: 'OR', label: 'Oregon' },
{ value: 'PA', label: 'Pennsylvania' },
{ value: 'RI', label: 'Rhode Island' },
{ value: 'SC', label: 'South Carolina' },
{ value: 'SD', label: 'South Dakota' },
{ value: 'TN', label: 'Tennessee' },
{ value: 'TX', label: 'Texas' },
{ value: 'UT', label: 'Utah' },
{ value: 'VT', label: 'Vermont' },
{ value: 'VA', label: 'Virginia' },
{ value: 'WA', label: 'Washington' },
{ value: 'WV', label: 'West Virginia' },
{ value: 'WI', label: 'Wisconsin' },
{ value: 'WY', label: 'Wyoming' },
],
};
export function getStatesList(country) {
return country && COUNTRY_STATES_MAP[country.toUpperCase()];
}

View File

@@ -7,7 +7,6 @@ import {
SAVE_PREVIOUS_SITE_LANGUAGE,
UPDATE_DRAFT,
RESET_DRAFTS,
SAVE_MULTIPLE_SETTINGS,
} from './actions';
import { reducer as deleteAccountReducer, DELETE_ACCOUNT } from '../delete-account';
@@ -145,24 +144,6 @@ const reducer = (state = defaultState, action) => {
...state,
previousSiteLanguage: action.payload.previousSiteLanguage,
};
case SAVE_MULTIPLE_SETTINGS.BEGIN:
return {
...state,
saveState: 'pending',
};
case SAVE_MULTIPLE_SETTINGS.SUCCESS:
return {
...state,
saveState: 'complete',
};
case SAVE_MULTIPLE_SETTINGS.FAILURE:
return {
...state,
saveState: 'error',
errors: Object.assign({}, state.errors, action.payload.errors),
};
case FETCH_TIME_ZONES.SUCCESS:
return {
@@ -196,7 +177,6 @@ const reducer = (state = defaultState, action) => {
case RESET_PASSWORD.BEGIN:
case RESET_PASSWORD.SUCCESS:
case RESET_PASSWORD.FORBIDDEN:
return {
...state,
resetPassword: resetPasswordReducer(state.resetPassword, action),

View File

@@ -12,7 +12,6 @@ import {
fetchSettingsFailure,
closeForm,
SAVE_SETTINGS,
SAVE_MULTIPLE_SETTINGS,
saveSettingsBegin,
saveSettingsSuccess,
saveSettingsFailure,
@@ -20,9 +19,6 @@ import {
FETCH_TIME_ZONES,
fetchTimeZones,
fetchTimeZonesSuccess,
saveMultipleSettingsBegin,
saveMultipleSettingsSuccess,
saveMultipleSettingsFailure,
} from './actions';
// Sub-modules
@@ -104,31 +100,6 @@ export function* handleSaveSettings(action) {
}
}
// handles mutiple settings saved at once, in order, and stops executing on first failure.
export function* handleSaveMultipleSettings(settings) {
try {
yield put(saveMultipleSettingsBegin());
const { username, userId } = getAuthenticatedUser();
const { settingsArray } = settings.payload;
for (let i = 0; i < settingsArray.length; i += 1) {
const { formId, commitValues } = settingsArray[i];
yield put(saveSettingsBegin());
const commitData = { [formId]: commitValues };
const savedSettings = yield call(patchSettings, username, commitData, userId);
yield put(saveSettingsSuccess(savedSettings, commitData));
}
yield put(saveMultipleSettingsSuccess(settings));
} catch (e) {
if (e.fieldErrors) {
yield put(saveMultipleSettingsFailure({ fieldErrors: e.fieldErrors }));
} else {
yield put(saveMultipleSettingsFailure(e.message));
throw e;
}
}
}
export function* handleFetchTimeZones(action) {
const response = yield call(getTimeZones, action.payload.country);
yield put(fetchTimeZonesSuccess(response, action.payload.country));
@@ -138,7 +109,6 @@ export function* handleFetchTimeZones(action) {
export default function* saga() {
yield takeEvery(FETCH_SETTINGS.BASE, handleFetchSettings);
yield takeEvery(SAVE_SETTINGS.BASE, handleSaveSettings);
yield takeEvery(SAVE_MULTIPLE_SETTINGS.BASE, handleSaveMultipleSettings);
yield takeEvery(FETCH_TIME_ZONES.BASE, handleFetchTimeZones);
yield all([
deleteAccountSaga(),

View File

@@ -73,6 +73,10 @@ export const staticFieldsSelector = createSelector(
accountSettings => (accountSettings.profileDataManager ? ['name', 'email', 'country'] : []),
);
export const hiddenFieldsSelector = createSelector(
accountSettingsSelector,
accountSettings => (accountSettings.profileDataManager ? [] : ['secondary_email']),
);
/**
* If there's no draft present at all (undefined), use the original committed value.
@@ -134,6 +138,7 @@ export const accountSettingsPageSelector = createSelector(
formValuesSelector,
profileDataManagerSelector,
staticFieldsSelector,
hiddenFieldsSelector,
timeZonesSelector,
countryTimeZonesSelector,
activeAccountSelector,
@@ -144,6 +149,7 @@ export const accountSettingsPageSelector = createSelector(
formValues,
profileDataManager,
staticFields,
hiddenFields,
timeZoneOptions,
countryTimeZoneOptions,
activeAccount,
@@ -159,6 +165,7 @@ export const accountSettingsPageSelector = createSelector(
formValues,
profileDataManager,
staticFields,
hiddenFields,
tpaProviders: accountSettings.thirdPartyAuth.providers,
}),
);
@@ -166,16 +173,16 @@ export const accountSettingsPageSelector = createSelector(
export const coachingConsentPageSelector = createSelector(
accountSettingsSelector,
formValuesSelector,
hiddenFieldsSelector,
activeAccountSelector,
profileDataManagerSelector,
saveStateSelector,
confirmationValuesSelector,
errorSelector,
(
accountSettings,
formValues,
hiddenFields,
activeAccount,
profileDataManager,
saveState,
confirmationValues,
errors,
@@ -184,8 +191,8 @@ export const coachingConsentPageSelector = createSelector(
loaded: accountSettings.loaded,
loadingError: accountSettings.loadingError,
isActive: activeAccount,
profileDataManager,
formValues,
hiddenFields,
saveState,
confirmationValues,
formErrors: errors,

View File

@@ -137,11 +137,12 @@ export async function getProfileDataManager(username, userRoles) {
const url = `${getConfig().LMS_BASE_URL}/enterprise/api/v1/enterprise-learner/?username=${username}`;
const { data } = await getAuthenticatedHttpClient().get(url).catch(handleRequestError);
if (data.results.length > 0) {
const enterprise = data.results[0] && data.results[0].enterprise_customer;
// To ensure that enterprise returned is current enterprise & it manages profile settings
if (enterprise && enterprise.sync_learner_profile_data) {
return enterprise.name;
if ('results' in data) {
for (let i = 0; i < data.results.length; i += 1) {
const enterprise = data.results[i].enterprise_customer;
if (enterprise.sync_learner_profile_data) {
return enterprise.name;
}
}
}
}
@@ -183,7 +184,7 @@ export async function patchSettings(username, commitValues, userId) {
// user/v1/preferences where it does update. This is the one we use.
const preferenceKeys = ['time_zone'];
const coachingKeys = ['coaching'];
const accountCommitValues = omit(commitValues, preferenceKeys, coachingKeys);
const accountCommitValues = omit(commitValues, preferenceKeys);
const preferenceCommitValues = pick(commitValues, preferenceKeys);
const coachingCommitValues = pick(commitValues, coachingKeys);
const patchRequests = [];

View File

@@ -27,10 +27,6 @@ export class AsyncActionType {
get RESET() {
return `${this.topic}__${this.name}__RESET`;
}
get FORBIDDEN() {
return `${this.topic}__${this.name}__FORBIDDEN`;
}
}
/**

View File

@@ -12,7 +12,6 @@ describe('AsyncActionType', () => {
expect(actionType.SUCCESS).toBe('HOUSE_CATS__START_THE_RACE__SUCCESS');
expect(actionType.FAILURE).toBe('HOUSE_CATS__START_THE_RACE__FAILURE');
expect(actionType.RESET).toBe('HOUSE_CATS__START_THE_RACE__RESET');
expect(actionType.FORBIDDEN).toBe('HOUSE_CATS__START_THE_RACE__FORBIDDEN');
});
});

View File

@@ -1,24 +0,0 @@
import React from 'react';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
import Alert from '../Alert';
const RequestInProgressAlert = (props) => {
return (
<Alert
className="alert-warning mt-n2"
icon={<FontAwesomeIcon className="mr-2" icon={faExclamationTriangle} />}
>
<FormattedMessage
id="account.settings.editable.field.password.reset.button.forbidden"
defaultMessage="Your previous request is in progress, please try again in few moments."
description="A message displayed when a previous password reset request is still in progress."
/>
</Alert>
);
};
export default RequestInProgressAlert;

View File

@@ -7,7 +7,6 @@ import { StatefulButton } from '@edx/paragon';
import { resetPassword } from './data/actions';
import messages from './messages';
import ConfirmationAlert from './ConfirmationAlert';
import RequestInProgressAlert from './RequestInProgressAlert';
const ResetPassword = (props) => {
const { email, intl, status } = props;
@@ -44,7 +43,6 @@ const ResetPassword = (props) => {
/>
</p>
{status === 'complete' ? <ConfirmationAlert email={email} /> : null}
{status === 'forbidden' ? <RequestInProgressAlert /> : null}
</div>
);
};

View File

@@ -18,7 +18,3 @@ export const resetPasswordSuccess = () => ({
export const resetPasswordReset = () => ({
type: RESET_PASSWORD.RESET,
});
export const resetPasswordForbidden = () => ({
type: RESET_PASSWORD.FORBIDDEN,
});

View File

@@ -17,11 +17,6 @@ const reducer = (state = defaultState, action = null) => {
...state,
status: 'complete',
};
case RESET_PASSWORD.FORBIDDEN:
return {
...state,
status: 'forbidden',
};
default:
}

View File

@@ -1,20 +1,12 @@
import { put, call, takeEvery } from 'redux-saga/effects';
import { resetPasswordBegin, resetPasswordForbidden, resetPasswordSuccess, RESET_PASSWORD } from './actions';
import { resetPasswordBegin, resetPasswordSuccess, RESET_PASSWORD } from './actions';
import { postResetPassword } from './service';
function* handleResetPassword(action) {
yield put(resetPasswordBegin());
try {
const response = yield call(postResetPassword, action.payload.email);
yield put(resetPasswordSuccess(response));
} catch (error) {
if (error.response && error.response.status === 403) {
yield put(resetPasswordForbidden(error));
} else {
throw error;
}
}
const response = yield call(postResetPassword, action.payload.email);
yield put(resetPasswordSuccess(response));
}
export default function* saga() {

View File

@@ -33,9 +33,6 @@
"account.settings.field.country": "Country",
"account.settings.field.country.empty": "Add country",
"account.settings.field.country.options.empty": "Select a Country",
"account.settings.field.state": "State",
"account.settings.field.state.empty": "Add state",
"account.settings.field.state.options.empty": "Select a State",
"account.settings.field.site.language": "Site language",
"account.settings.field.site.language.help.text": "The language used throughout this site. This site is currently available in a limited number of languages.",
"account.settings.field.education": "Education",
@@ -79,23 +76,10 @@
"account.settings.editable.field.action.edit": "Edit",
"account.settings.static.field.empty": "No value set. Contact your {enterprise} administrator to make changes.",
"account.settings.static.field.empty.no.admin": "No value set.",
"account.settings.coaching.consent.welcome.header": "Lets get started.",
"account.settings.coaching.consent.welcome.subheader": "We're here for you from start to finish",
"account.settings.coaching.consent.description": "MicroBachelors programs include coaching that focuses on your career, education, and how you'll achieve results through one-on-one communication with an experienced professional. If youre interested, provide the information below and click “Submit,” and our coaching partner will connect with you via email and/or text message to help you move forward. Terms and conditions apply.*",
"account.settings.coaching.consent.text-messaging.disclaimer": "* Coaching services are included at no additional cost to learners with US phone numbers. Coaching includes recurring text messages. Message and data rates may apply. Text STOP to opt-out.",
"account.settings.coaching.consent.accept-coaching": "Sign up for coaching",
"account.settings.coaching.consent.decline-coaching": "I prefer not to be contacted with free coaching services",
"account.settings.coaching.consent.label.name": "Please confirm your name",
"account.settings.coaching.consent.label.phone-number": "Enter your mobile number",
"account.settings.coaching.consent.success.header": "Success!",
"account.settings.coaching.consent.success.message": "You're signed up for coaching. You will receive a text message confirmation.",
"account.settings.coaching.consent.success.continue": "Start my course",
"account.settings.coaching.managed.support": "support",
"account.settings.coaching.managed.alert": "Your name is managed by {managerTitle}. Contact your administrator for help.",
"account.settings.field.phone_number": "Phone Number",
"account.settings.field.phone_number.empty": "Add a phone number",
"account.settings.field.coaching_consent": "Coaching consent",
"account.settings.field.coaching_consent.tooltip": "MicroBachelors programs include text message based coaching that helps you pair educational experiences with your career goals through one-on-one advice. Coaching services are included at no additional cost, and are available to learners with U.S. mobile phone numbers. Standard messaging rates apply. Text STOP at anytime to opt-out of messages.",
"account.settings.field.coaching_consent.tooltip": "MicroBachelors programs include text message based coaching that helps you pair educational experiences with your career goals through one-on-one advice. Coaching services are included at no additional cost, and are available in English and Spanish languages. Standard messaging rates apply. Text STOP at anytime to opt-out of messages.",
"account.settings.field.coaching_consent.error": "A valid US phone number is required to opt into coaching",
"account.settings.delete.account.before.proceeding": "Before proceeding, please {actionLink}.",
"account.settings.delete.account.header": "Delete My Account",
@@ -125,7 +109,6 @@
"account.settings.editable.field.password.reset.button.confirmation.support.link": "technical support",
"account.settings.editable.field.password.reset.button.confirmation": "We've sent a message to {email}. Click the link in the message to reset your password. Didn't receive the message? Contact {technicalSupportLink}.",
"account.settings.editable.field.password.reset.button": "Reset Password",
"account.settings.editable.field.password.reset.button.forbidden": "Your previous request is in progress, please try again in few moments.",
"account.settings.editable.field.password.reset.label": "Password",
"account.settings.sso.link.account": "Sign in with {name}",
"account.settings.sso.account.connected": "Linked",

View File

@@ -33,9 +33,6 @@
"account.settings.field.country": "País",
"account.settings.field.country.empty": "Agregar país",
"account.settings.field.country.options.empty": "Seleccionar un país",
"account.settings.field.state": "Estado",
"account.settings.field.state.empty": "Add state",
"account.settings.field.state.options.empty": "Select a State",
"account.settings.field.site.language": "Idioma del sitio",
"account.settings.field.site.language.help.text": "El idioma que se usará para el sitio. Actualmente solo hay disponibilidad de usar un número limitado de idiomas.",
"account.settings.field.education": "Educación",
@@ -77,25 +74,12 @@
"account.settings.editable.field.action.save": "Guardar",
"account.settings.editable.field.action.cancel": "Cancelar",
"account.settings.editable.field.action.edit": "Editar",
"account.settings.static.field.empty": "No hay valor establecido. Contacte su administrador {enterprise} para hacer cambios.",
"account.settings.static.field.empty.no.admin": "No hay valor establecido.",
"account.settings.coaching.consent.welcome.header": "Lets get started.",
"account.settings.coaching.consent.welcome.subheader": "We're here for you from start to finish",
"account.settings.coaching.consent.description": "MicroBachelors programs include coaching that focuses on your career, education, and how you'll achieve results through one-on-one communication with an experienced professional. If youre interested, provide the information below and click “Submit,” and our coaching partner will connect with you via email and/or text message to help you move forward. Terms and conditions apply.*",
"account.settings.coaching.consent.text-messaging.disclaimer": "* Coaching services are included at no additional cost to learners with US phone numbers. Coaching includes recurring text messages. Message and data rates may apply. Text STOP to opt-out.",
"account.settings.coaching.consent.accept-coaching": "Sign up for coaching",
"account.settings.coaching.consent.decline-coaching": "I prefer not to be contacted with free coaching services",
"account.settings.coaching.consent.label.name": "Please confirm your name",
"account.settings.coaching.consent.label.phone-number": "Enter your mobile number",
"account.settings.coaching.consent.success.header": "Success!",
"account.settings.coaching.consent.success.message": "You're signed up for coaching. You will receive a text message confirmation.",
"account.settings.coaching.consent.success.continue": "Start my course",
"account.settings.coaching.managed.support": "soporte",
"account.settings.coaching.managed.alert": "Your name is managed by {managerTitle}. Contact your administrator for help.",
"account.settings.field.phone_number": "Teléfono",
"account.settings.static.field.empty": "No value set. Contact your {enterprise} administrator to make changes.",
"account.settings.static.field.empty.no.admin": "No value set.",
"account.settings.field.phone_number": "Phone Number",
"account.settings.field.phone_number.empty": "Add a phone number",
"account.settings.field.coaching_consent": "Coaching consent",
"account.settings.field.coaching_consent.tooltip": "MicroBachelors programs include text message based coaching that helps you pair educational experiences with your career goals through one-on-one advice. Coaching services are included at no additional cost, and are available to learners with U.S. mobile phone numbers. Standard messaging rates apply. Text STOP at anytime to opt-out of messages.",
"account.settings.field.coaching_consent.tooltip": "MicroBachelors programs include text message based coaching that helps you pair educational experiences with your career goals through one-on-one advice. Coaching services are included at no additional cost, and are available in English and Spanish languages. Standard messaging rates apply. Text STOP at anytime to opt-out of messages.",
"account.settings.field.coaching_consent.error": "A valid US phone number is required to opt into coaching",
"account.settings.delete.account.before.proceeding": "Antes de continuar, por favor {actionLink}.",
"account.settings.delete.account.header": "Eliminar mi cuenta",
@@ -107,7 +91,7 @@
"account.settings.delete.account.text.change.instead": "En lugar de eso, ¿quieres cambiar tu correo electrónico, nombre o contraseña?",
"account.settings.delete.account.button": "Eliminar mi cuenta",
"account.settings.delete.account.please.activate": "activar su cuenta",
"account.settings.delete.account.please.unlink": "Desvincular todas las cuentas de redes sociales.",
"account.settings.delete.account.please.unlink": "unlink all social media accounts",
"account.settings.delete.account.modal.header": "¿Está seguro?",
"account.settings.delete.account.modal.text.1": "Has seleccionado “Eliminar mi cuenta”. La eliminación de tu cuenta y datos personales es permanente e irreversible. edX no será capaz de recuperar tu cuenta o los datos que se hayan borrado.",
"account.settings.delete.account.modal.text.2": "Si procedes, no será posible usar esta cuenta para tomar cursos ni en la aplicación móvil de edX, ni en edx.org, ni en cualquier otro sitio hospedado por edX. Esto incluye el acceso a edx.org desde el sistema de tu empleador o universidad, y el acceso a sitios privados ofrecidos por MIT Open Learning, Wharton Executive Education, y Harvard Medical School.",
@@ -125,11 +109,10 @@
"account.settings.editable.field.password.reset.button.confirmation.support.link": "soporte técnico",
"account.settings.editable.field.password.reset.button.confirmation": "Hemos mandado un mensaje a {email}. Haz clic en el enlace en el mensaje para restablecer tu contraseña. ¿No recibiste el mensaje? Contáctate con {technicalSupportLink}.",
"account.settings.editable.field.password.reset.button": "Restablecer contraseña",
"account.settings.editable.field.password.reset.button.forbidden": "Your previous request is in progress, please try again in few moments.",
"account.settings.editable.field.password.reset.label": "Contraseña",
"account.settings.sso.link.account": "Iniciar sesión con {name}",
"account.settings.sso.account.connected": "Vinculado",
"account.settings.sso.account.disconnect.error": "Hubo un problema al desconectar esta Cuenta. Si el problema persiste, contacte soporte.",
"account.settings.sso.account.disconnect.error": "There was a problem disconnecting this account. Contact support if the problem persists.",
"account.settings.sso.unlink.account": "Desvincular la cuenta de {accountName} ",
"account.settings.sso.no.providers": "No se pueden vincular cuentas en este momento."
"account.settings.sso.no.providers": "No accounts can be linked at this time."
}

View File

@@ -33,9 +33,6 @@
"account.settings.field.country": "Country",
"account.settings.field.country.empty": "Add country",
"account.settings.field.country.options.empty": "Select a Country",
"account.settings.field.state": "State",
"account.settings.field.state.empty": "Add state",
"account.settings.field.state.options.empty": "Select a State",
"account.settings.field.site.language": "Site language",
"account.settings.field.site.language.help.text": "The language used throughout this site. This site is currently available in a limited number of languages.",
"account.settings.field.education": "Education",
@@ -79,23 +76,10 @@
"account.settings.editable.field.action.edit": "Edit",
"account.settings.static.field.empty": "No value set. Contact your {enterprise} administrator to make changes.",
"account.settings.static.field.empty.no.admin": "No value set.",
"account.settings.coaching.consent.welcome.header": "Lets get started.",
"account.settings.coaching.consent.welcome.subheader": "We're here for you from start to finish",
"account.settings.coaching.consent.description": "MicroBachelors programs include coaching that focuses on your career, education, and how you'll achieve results through one-on-one communication with an experienced professional. If youre interested, provide the information below and click “Submit,” and our coaching partner will connect with you via email and/or text message to help you move forward. Terms and conditions apply.*",
"account.settings.coaching.consent.text-messaging.disclaimer": "* Coaching services are included at no additional cost to learners with US phone numbers. Coaching includes recurring text messages. Message and data rates may apply. Text STOP to opt-out.",
"account.settings.coaching.consent.accept-coaching": "Sign up for coaching",
"account.settings.coaching.consent.decline-coaching": "I prefer not to be contacted with free coaching services",
"account.settings.coaching.consent.label.name": "Please confirm your name",
"account.settings.coaching.consent.label.phone-number": "Enter your mobile number",
"account.settings.coaching.consent.success.header": "Success!",
"account.settings.coaching.consent.success.message": "You're signed up for coaching. You will receive a text message confirmation.",
"account.settings.coaching.consent.success.continue": "Start my course",
"account.settings.coaching.managed.support": "support",
"account.settings.coaching.managed.alert": "Your name is managed by {managerTitle}. Contact your administrator for help.",
"account.settings.field.phone_number": "Phone Number",
"account.settings.field.phone_number.empty": "Add a phone number",
"account.settings.field.coaching_consent": "Coaching consent",
"account.settings.field.coaching_consent.tooltip": "MicroBachelors programs include text message based coaching that helps you pair educational experiences with your career goals through one-on-one advice. Coaching services are included at no additional cost, and are available to learners with U.S. mobile phone numbers. Standard messaging rates apply. Text STOP at anytime to opt-out of messages.",
"account.settings.field.coaching_consent.tooltip": "MicroBachelors programs include text message based coaching that helps you pair educational experiences with your career goals through one-on-one advice. Coaching services are included at no additional cost, and are available in English and Spanish languages. Standard messaging rates apply. Text STOP at anytime to opt-out of messages.",
"account.settings.field.coaching_consent.error": "A valid US phone number is required to opt into coaching",
"account.settings.delete.account.before.proceeding": "Before proceeding, please {actionLink}.",
"account.settings.delete.account.header": "Delete My Account",
@@ -125,7 +109,6 @@
"account.settings.editable.field.password.reset.button.confirmation.support.link": "technical support",
"account.settings.editable.field.password.reset.button.confirmation": "We've sent a message to {email}. Click the link in the message to reset your password. Didn't receive the message? Contact {technicalSupportLink}.",
"account.settings.editable.field.password.reset.button": "Reset Password",
"account.settings.editable.field.password.reset.button.forbidden": "Your previous request is in progress, please try again in few moments.",
"account.settings.editable.field.password.reset.label": "Password",
"account.settings.sso.link.account": "Sign in with {name}",
"account.settings.sso.account.connected": "Linked",

View File

@@ -33,9 +33,6 @@
"account.settings.field.country": "Country",
"account.settings.field.country.empty": "Add country",
"account.settings.field.country.options.empty": "Select a Country",
"account.settings.field.state": "State",
"account.settings.field.state.empty": "Add state",
"account.settings.field.state.options.empty": "Select a State",
"account.settings.field.site.language": "Site language",
"account.settings.field.site.language.help.text": "The language used throughout this site. This site is currently available in a limited number of languages.",
"account.settings.field.education": "Education",
@@ -79,23 +76,10 @@
"account.settings.editable.field.action.edit": "Edit",
"account.settings.static.field.empty": "No value set. Contact your {enterprise} administrator to make changes.",
"account.settings.static.field.empty.no.admin": "No value set.",
"account.settings.coaching.consent.welcome.header": "Lets get started.",
"account.settings.coaching.consent.welcome.subheader": "We're here for you from start to finish",
"account.settings.coaching.consent.description": "MicroBachelors programs include coaching that focuses on your career, education, and how you'll achieve results through one-on-one communication with an experienced professional. If youre interested, provide the information below and click “Submit,” and our coaching partner will connect with you via email and/or text message to help you move forward. Terms and conditions apply.*",
"account.settings.coaching.consent.text-messaging.disclaimer": "* Coaching services are included at no additional cost to learners with US phone numbers. Coaching includes recurring text messages. Message and data rates may apply. Text STOP to opt-out.",
"account.settings.coaching.consent.accept-coaching": "Sign up for coaching",
"account.settings.coaching.consent.decline-coaching": "I prefer not to be contacted with free coaching services",
"account.settings.coaching.consent.label.name": "Please confirm your name",
"account.settings.coaching.consent.label.phone-number": "Enter your mobile number",
"account.settings.coaching.consent.success.header": "Success!",
"account.settings.coaching.consent.success.message": "You're signed up for coaching. You will receive a text message confirmation.",
"account.settings.coaching.consent.success.continue": "Start my course",
"account.settings.coaching.managed.support": "support",
"account.settings.coaching.managed.alert": "Your name is managed by {managerTitle}. Contact your administrator for help.",
"account.settings.field.phone_number": "Phone Number",
"account.settings.field.phone_number.empty": "Add a phone number",
"account.settings.field.coaching_consent": "Coaching consent",
"account.settings.field.coaching_consent.tooltip": "MicroBachelors programs include text message based coaching that helps you pair educational experiences with your career goals through one-on-one advice. Coaching services are included at no additional cost, and are available to learners with U.S. mobile phone numbers. Standard messaging rates apply. Text STOP at anytime to opt-out of messages.",
"account.settings.field.coaching_consent.tooltip": "MicroBachelors programs include text message based coaching that helps you pair educational experiences with your career goals through one-on-one advice. Coaching services are included at no additional cost, and are available in English and Spanish languages. Standard messaging rates apply. Text STOP at anytime to opt-out of messages.",
"account.settings.field.coaching_consent.error": "A valid US phone number is required to opt into coaching",
"account.settings.delete.account.before.proceeding": "Before proceeding, please {actionLink}.",
"account.settings.delete.account.header": "Delete My Account",
@@ -125,7 +109,6 @@
"account.settings.editable.field.password.reset.button.confirmation.support.link": "technical support",
"account.settings.editable.field.password.reset.button.confirmation": "We've sent a message to {email}. Click the link in the message to reset your password. Didn't receive the message? Contact {technicalSupportLink}.",
"account.settings.editable.field.password.reset.button": "Reset Password",
"account.settings.editable.field.password.reset.button.forbidden": "Your previous request is in progress, please try again in few moments.",
"account.settings.editable.field.password.reset.label": "Password",
"account.settings.sso.link.account": "Sign in with {name}",
"account.settings.sso.account.connected": "Linked",

View File

@@ -31,10 +31,10 @@ subscribe(APP_READY, () => {
ReactDOM.render(
<AppProvider store={configureStore()}>
<Switch>
<Route path="/coaching_consent" component={CoachingConsent} />
<Route path="coaching_consent" component={CoachingConsent} />
<HeaderFooterLayout>
<Route exact path="/" component={AccountSettingsPage} />
<Route path="/notfound" component={NotFoundPage} />
<Route exact path="" component={AccountSettingsPage} />
<Route path="notfound" component={NotFoundPage} />
<Route path="*" component={NotFoundPage} />
</HeaderFooterLayout>
</Switch>