Compare commits
34 Commits
kdmccormic
...
ttracy/MB-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f413c05a1 | ||
|
|
9478a3f215 | ||
|
|
d58c5803be | ||
|
|
a868df9b72 | ||
|
|
2bc7b4ee00 | ||
|
|
8894ab7317 | ||
|
|
c337e03a4d | ||
|
|
c6aedbea29 | ||
|
|
6e099457db | ||
|
|
54fa5b970a | ||
|
|
38371d1a46 | ||
|
|
f805480e21 | ||
|
|
cc3bf06a6f | ||
|
|
0e8d7622c6 | ||
|
|
9faf28203b | ||
|
|
e94d05d9e2 | ||
|
|
8b4f7818fc | ||
|
|
f18c71d13a | ||
|
|
a1aeb7035e | ||
|
|
ef85448e27 | ||
|
|
741cfb6aac | ||
|
|
c808c8c0a1 | ||
|
|
4eb96e64c7 | ||
|
|
f1ec989054 | ||
|
|
54032e6ec5 | ||
|
|
ef5c303fbc | ||
|
|
caa06a08b0 | ||
|
|
5e4278ea5a | ||
|
|
96dc3f7e3f | ||
|
|
5726be2805 | ||
|
|
73c66d5d18 | ||
|
|
19ef66cf42 | ||
|
|
c83d76e1a9 | ||
|
|
2f2abd54ff |
@@ -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/login'
|
||||
LOGOUT_URL='http://localhost:18000/logout'
|
||||
MARKETING_SITE_BASE_URL='http://localhost:18000'
|
||||
NODE_ENV='development'
|
||||
ORDER_HISTORY_URL='localhost:1996/orders'
|
||||
@@ -17,4 +17,4 @@ 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=''
|
||||
COACHING_ENABLED=true
|
||||
|
||||
@@ -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/login'
|
||||
LOGOUT_URL='http://localhost:18000/logout'
|
||||
MARKETING_SITE_BASE_URL='http://localhost:18000'
|
||||
NODE_ENV=null
|
||||
ORDER_HISTORY_URL='localhost:1996/orders'
|
||||
|
||||
@@ -31,9 +31,12 @@ 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';
|
||||
import DemographicsSection from './demographics/DemographicsSection';
|
||||
|
||||
class AccountSettingsPage extends React.Component {
|
||||
constructor(props, context) {
|
||||
@@ -82,11 +85,15 @@ class AccountSettingsPage extends React.Component {
|
||||
return concatTimeZoneOptions;
|
||||
});
|
||||
|
||||
getLocalizedOptions = memoize(locale => ({
|
||||
getLocalizedOptions = memoize((locale, country) => ({
|
||||
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']),
|
||||
@@ -209,11 +216,15 @@ class AccountSettingsPage extends React.Component {
|
||||
// Memoized options lists
|
||||
const {
|
||||
countryOptions,
|
||||
stateOptions,
|
||||
languageProficiencyOptions,
|
||||
yearOfBirthOptions,
|
||||
educationLevelOptions,
|
||||
genderOptions,
|
||||
} = this.getLocalizedOptions(this.context.locale);
|
||||
} = 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;
|
||||
|
||||
const timeZoneOptions = this.getLocalizedTimeZoneOptions(
|
||||
this.props.timeZoneOptions,
|
||||
@@ -294,6 +305,22 @@ 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">
|
||||
@@ -338,6 +365,8 @@ class AccountSettingsPage extends React.Component {
|
||||
}
|
||||
</div>
|
||||
|
||||
<DemographicsSection />
|
||||
|
||||
<div className="account-section" id="social-media">
|
||||
<h2 className="section-heading">
|
||||
{this.props.intl.formatMessage(messages['account.settings.section.social.media'])}
|
||||
@@ -488,11 +517,11 @@ AccountSettingsPage.propTypes = {
|
||||
social_link_facebook: PropTypes.string,
|
||||
social_link_twitter: PropTypes.string,
|
||||
time_zone: PropTypes.string,
|
||||
coaching: PropTypes.objectOf(PropTypes.shape({
|
||||
coaching_consent: PropTypes.string.isRequired,
|
||||
coaching: PropTypes.shape({
|
||||
coaching_consent: PropTypes.bool.isRequired,
|
||||
user: PropTypes.number.isRequired,
|
||||
eligible_for_coaching: PropTypes.bool.isRequired,
|
||||
})),
|
||||
}),
|
||||
}).isRequired,
|
||||
siteLanguage: PropTypes.shape({
|
||||
previousValue: PropTypes.string,
|
||||
|
||||
@@ -46,6 +46,11 @@ const messages = defineMessages({
|
||||
defaultMessage: 'Profile Information',
|
||||
description: 'The profile information section heading.',
|
||||
},
|
||||
'account.settings.section.demographics.information': {
|
||||
id: 'account.settings.section.demographics.information',
|
||||
defaultMessage: 'Optional Information',
|
||||
description: 'The optional information section heading.',
|
||||
},
|
||||
'account.settings.section.site.preferences': {
|
||||
id: 'account.settings.section.site.preferences',
|
||||
defaultMessage: 'Site Preferences',
|
||||
@@ -156,6 +161,21 @@ 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',
|
||||
@@ -272,6 +292,7 @@ const messages = defineMessages({
|
||||
defaultMessage: 'Select a Language',
|
||||
description: 'Option for an empty value on account settings spoken languages field.',
|
||||
},
|
||||
|
||||
'account.settings.field.time.zone': {
|
||||
id: 'account.settings.field.time.zone',
|
||||
defaultMessage: 'Time zone',
|
||||
|
||||
@@ -39,7 +39,6 @@ function EditableField(props) {
|
||||
...others
|
||||
} = props;
|
||||
const id = `field-${name}`;
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
onSubmit(name, new FormData(e.target).get(name));
|
||||
@@ -106,6 +105,7 @@ function EditableField(props) {
|
||||
options={options}
|
||||
{...others}
|
||||
/>
|
||||
{!!others.children && <>{others.children}</>}
|
||||
</ValidationFormGroup>
|
||||
<p>
|
||||
<StatefulButton
|
||||
|
||||
@@ -13,6 +13,7 @@ function JumpNav({ intl }) {
|
||||
items={[
|
||||
'basic-information',
|
||||
'profile-information',
|
||||
'demographics-information',
|
||||
'social-media',
|
||||
'site-preferences',
|
||||
'linked-accounts',
|
||||
@@ -31,6 +32,11 @@ function JumpNav({ intl }) {
|
||||
{intl.formatMessage(messages['account.settings.section.profile.information'])}
|
||||
</NavHashLink>
|
||||
</li>
|
||||
<li>
|
||||
<NavHashLink to="#demographics-information">
|
||||
{intl.formatMessage(messages['account.settings.section.demographics.information'])}
|
||||
</NavHashLink>
|
||||
</li>
|
||||
<li>
|
||||
<NavHashLink to="#social-media">
|
||||
{intl.formatMessage(messages['account.settings.section.social.media'])}
|
||||
|
||||
@@ -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 } from '../data/actions';
|
||||
import { fetchSettings, saveSettings, saveMultipleSettings } from '../data/actions';
|
||||
import { coachingConsentPageSelector } from '../data/selectors';
|
||||
|
||||
const Logo = ({ src, alt, ...attributes }) => (
|
||||
@@ -96,9 +96,7 @@ class CoachingConsent extends React.Component {
|
||||
// Check if all values from the form have confirmation values
|
||||
if (
|
||||
this.state.formSubmitted &&
|
||||
this.props.confirmationValues.coaching &&
|
||||
this.props.confirmationValues.name &&
|
||||
this.props.confirmationValues.phone_number
|
||||
this.props.saveState === 'complete'
|
||||
) {
|
||||
allSubmissionsComplete = true;
|
||||
}
|
||||
@@ -125,21 +123,39 @@ 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;
|
||||
|
||||
// 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,
|
||||
});
|
||||
// !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);
|
||||
}
|
||||
|
||||
async declineCoaching(e) {
|
||||
@@ -147,6 +163,7 @@ 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;
|
||||
@@ -168,6 +185,7 @@ 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..." />;
|
||||
@@ -191,7 +209,6 @@ 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;
|
||||
@@ -260,6 +277,8 @@ AutoRedirect.propTypes = {
|
||||
|
||||
CoachingConsent.defaultProps = {
|
||||
loaded: false,
|
||||
saveState: undefined,
|
||||
profileDataManager: null,
|
||||
};
|
||||
|
||||
CoachingConsent.propTypes = {
|
||||
@@ -285,9 +304,13 @@ 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));
|
||||
|
||||
@@ -56,6 +56,11 @@ 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;
|
||||
|
||||
@@ -1,15 +1,30 @@
|
||||
import React from 'react';
|
||||
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { injectIntl, intlShape, FormattedMessage } 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">
|
||||
@@ -19,12 +34,17 @@ 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>
|
||||
@@ -91,6 +111,7 @@ CoachingForm.propTypes = {
|
||||
phone_number: PropTypes.string,
|
||||
}),
|
||||
redirectUrl: PropTypes.string.isRequired,
|
||||
profileDataManager: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
ErrorMessage.defaultProps = {
|
||||
@@ -101,4 +122,9 @@ ErrorMessage.propTypes = {
|
||||
message: PropTypes.string,
|
||||
};
|
||||
|
||||
ManagedProfileAlert.propTypes = {
|
||||
profileDataManager: PropTypes.string.isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
export default injectIntl(CoachingForm);
|
||||
|
||||
@@ -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 } from '../data/actions';
|
||||
import { saveSettings, updateDraft, saveMultipleSettings } from '../data/actions';
|
||||
import EditableField from '../EditableField';
|
||||
|
||||
|
||||
@@ -18,7 +18,25 @@ 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={props.saveSettings}
|
||||
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);
|
||||
}}
|
||||
/>
|
||||
<ValidationFormGroup
|
||||
for="coachingConsent"
|
||||
@@ -37,9 +55,11 @@ 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 = {
|
||||
...props.coaching,
|
||||
phone_number: props.phone_number,
|
||||
user,
|
||||
eligible_for_coaching,
|
||||
coaching_consent: e.target.checked,
|
||||
};
|
||||
props.saveSettings(name, value);
|
||||
@@ -53,18 +73,20 @@ const CoachingToggle = props => (
|
||||
CoachingToggle.defaultProps = {
|
||||
phone_number: '',
|
||||
error: '',
|
||||
saveState: undefined,
|
||||
};
|
||||
|
||||
CoachingToggle.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
error: PropTypes.string,
|
||||
coaching: PropTypes.objectOf(PropTypes.shape({
|
||||
coaching_consent: PropTypes.string.isRequired,
|
||||
coaching: PropTypes.shape({
|
||||
coaching_consent: PropTypes.bool.isRequired,
|
||||
user: PropTypes.number.isRequired,
|
||||
eligible_for_coaching: PropTypes.bool.isRequired,
|
||||
})).isRequired,
|
||||
saveState: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
saveState: PropTypes.oneOf(['default', 'pending', 'complete', 'error']),
|
||||
saveSettings: PropTypes.func.isRequired,
|
||||
saveMultipleSettings: PropTypes.func.isRequired,
|
||||
updateDraft: PropTypes.func.isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
phone_number: PropTypes.string,
|
||||
@@ -73,4 +95,5 @@ CoachingToggle.propTypes = {
|
||||
export default connect(editableFieldSelector, {
|
||||
saveSettings,
|
||||
updateDraft,
|
||||
saveMultipleSettings,
|
||||
})(injectIntl(CoachingToggle));
|
||||
|
||||
@@ -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 in English and Spanish languages. 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 to learners with U.S. mobile phone numbers. 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': {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
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
|
||||
@@ -7,21 +8,20 @@ import { getConfig } from '@edx/frontend-platform';
|
||||
* @param {Number} userId users are identified in the api by LMS id
|
||||
*/
|
||||
export async function getCoachingPreferences(userId) {
|
||||
let data = null;
|
||||
let data = {};
|
||||
try {
|
||||
({ data } = await getAuthenticatedHttpClient()
|
||||
.get(`${getConfig().LMS_BASE_URL}/api/coaching/v1/users/${userId}/`));
|
||||
} catch (error) {
|
||||
// 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.
|
||||
// If a user isn't active the API call will fail with a lack of credentials.
|
||||
data = {
|
||||
coaching_consent: false,
|
||||
user: userId,
|
||||
eligible_for_coaching: true,
|
||||
eligible_for_coaching: false,
|
||||
consent_form_seen: false,
|
||||
};
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -40,9 +40,11 @@ export async function patchCoachingPreferences(userId, commitValues) {
|
||||
.catch((error) => {
|
||||
const apiError = Object.create(error);
|
||||
apiError.fieldErrors = JSON.parse(error.customAttributes.httpErrorResponseData);
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
apiError.fieldErrors.coaching = apiError.fieldErrors.phone_number[0];
|
||||
delete apiError.fieldErrors.phone_number;
|
||||
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;
|
||||
}
|
||||
throw apiError;
|
||||
});
|
||||
return commitValues;
|
||||
|
||||
@@ -2,6 +2,7 @@ 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';
|
||||
@@ -99,6 +100,25 @@ 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 => ({
|
||||
|
||||
@@ -31,4 +31,173 @@ 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()];
|
||||
}
|
||||
|
||||
export const SELF_DESCRIBE = 'self-describe'
|
||||
export const DEMOGRAPHICS_GENDER_OPTIONS = [
|
||||
'',
|
||||
'woman',
|
||||
'man',
|
||||
'non-binary',
|
||||
SELF_DESCRIBE,
|
||||
];
|
||||
|
||||
export const DEMOGRAPHICS_ETHNICITY_OPTIONS = [
|
||||
'',
|
||||
'american-indian-or-alaska-native',
|
||||
'asian',
|
||||
'black-or-african-american',
|
||||
'hispanic-latin-spanish',
|
||||
'middle-eastern-or-north-african',
|
||||
'native-hawaiian-or-pacific-islander',
|
||||
'white',
|
||||
'other',
|
||||
];
|
||||
|
||||
export const DEMOGRAPHICS_INCOME_OPTIONS = [
|
||||
'',
|
||||
'less-than-10k',
|
||||
'10k-25k',
|
||||
'25k-50k',
|
||||
'50k-75k',
|
||||
'over-100k',
|
||||
'unsure',
|
||||
]
|
||||
|
||||
export const DEMOGRAPHICS_MILITARY_HISTORY_OPTIONS = [
|
||||
'',
|
||||
'never-served',
|
||||
'training',
|
||||
'active',
|
||||
'previously-active',
|
||||
]
|
||||
|
||||
export const DEMOGRAPHICS_EDUCATION_LEVEL_OPTIONS = [
|
||||
'',
|
||||
'no-high-school',
|
||||
'some-high-school',
|
||||
'high-school-ged-equivalent',
|
||||
'some-college',
|
||||
'associates',
|
||||
'bachelors',
|
||||
'masters',
|
||||
'professional',
|
||||
'doctorate',
|
||||
]
|
||||
|
||||
export const DEMOGRAPHICS_WORK_STATUS_OPTIONS = [
|
||||
'',
|
||||
'full-time',
|
||||
'part-time',
|
||||
'not-employed-looking',
|
||||
'not-employed-not-looking',
|
||||
'unable',
|
||||
'retired',
|
||||
'other',
|
||||
]
|
||||
|
||||
export const DEMOGRAPHICS_WORK_SECTOR_OPTIONS = [
|
||||
'',
|
||||
'accommodation-food',
|
||||
'administrative-support-waste-remediation',
|
||||
'agriculture-forestry-fishing-hunting',
|
||||
'arts-entertainment-recreation',
|
||||
'construction',
|
||||
'educational',
|
||||
'finance-insurance',
|
||||
'healthcare-social',
|
||||
'information',
|
||||
'management',
|
||||
'manufacturing',
|
||||
'mining-quarry-oil-gas',
|
||||
'professional-scientific-technical',
|
||||
'public-admin',
|
||||
'real-estate',
|
||||
'retail',
|
||||
'transport-warehousing',
|
||||
'utilities',
|
||||
'trade',
|
||||
'other',
|
||||
]
|
||||
|
||||
export const DECLINED = 'declined'
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
SAVE_PREVIOUS_SITE_LANGUAGE,
|
||||
UPDATE_DRAFT,
|
||||
RESET_DRAFTS,
|
||||
SAVE_MULTIPLE_SETTINGS,
|
||||
} from './actions';
|
||||
|
||||
import { reducer as deleteAccountReducer, DELETE_ACCOUNT } from '../delete-account';
|
||||
@@ -144,6 +145,24 @@ 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 {
|
||||
@@ -177,6 +196,7 @@ const reducer = (state = defaultState, action) => {
|
||||
|
||||
case RESET_PASSWORD.BEGIN:
|
||||
case RESET_PASSWORD.SUCCESS:
|
||||
case RESET_PASSWORD.FORBIDDEN:
|
||||
return {
|
||||
...state,
|
||||
resetPassword: resetPasswordReducer(state.resetPassword, action),
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
fetchSettingsFailure,
|
||||
closeForm,
|
||||
SAVE_SETTINGS,
|
||||
SAVE_MULTIPLE_SETTINGS,
|
||||
saveSettingsBegin,
|
||||
saveSettingsSuccess,
|
||||
saveSettingsFailure,
|
||||
@@ -19,6 +20,9 @@ import {
|
||||
FETCH_TIME_ZONES,
|
||||
fetchTimeZones,
|
||||
fetchTimeZonesSuccess,
|
||||
saveMultipleSettingsBegin,
|
||||
saveMultipleSettingsSuccess,
|
||||
saveMultipleSettingsFailure,
|
||||
} from './actions';
|
||||
|
||||
// Sub-modules
|
||||
@@ -100,6 +104,31 @@ 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));
|
||||
@@ -109,6 +138,7 @@ 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(),
|
||||
|
||||
@@ -167,6 +167,7 @@ export const coachingConsentPageSelector = createSelector(
|
||||
accountSettingsSelector,
|
||||
formValuesSelector,
|
||||
activeAccountSelector,
|
||||
profileDataManagerSelector,
|
||||
saveStateSelector,
|
||||
confirmationValuesSelector,
|
||||
errorSelector,
|
||||
@@ -174,6 +175,7 @@ export const coachingConsentPageSelector = createSelector(
|
||||
accountSettings,
|
||||
formValues,
|
||||
activeAccount,
|
||||
profileDataManager,
|
||||
saveState,
|
||||
confirmationValues,
|
||||
errors,
|
||||
@@ -182,9 +184,19 @@ export const coachingConsentPageSelector = createSelector(
|
||||
loaded: accountSettings.loaded,
|
||||
loadingError: accountSettings.loadingError,
|
||||
isActive: activeAccount,
|
||||
profileDataManager,
|
||||
formValues,
|
||||
saveState,
|
||||
confirmationValues,
|
||||
formErrors: errors,
|
||||
}),
|
||||
);
|
||||
|
||||
export const demographicsSectionSelector = createSelector(
|
||||
formValuesSelector,
|
||||
(
|
||||
formValues,
|
||||
) => ({
|
||||
formValues,
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -137,12 +137,11 @@ 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 ('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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,7 +183,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);
|
||||
const accountCommitValues = omit(commitValues, preferenceKeys, coachingKeys);
|
||||
const preferenceCommitValues = pick(commitValues, preferenceKeys);
|
||||
const coachingCommitValues = pick(commitValues, coachingKeys);
|
||||
const patchRequests = [];
|
||||
|
||||
@@ -27,6 +27,10 @@ export class AsyncActionType {
|
||||
get RESET() {
|
||||
return `${this.topic}__${this.name}__RESET`;
|
||||
}
|
||||
|
||||
get FORBIDDEN() {
|
||||
return `${this.topic}__${this.name}__FORBIDDEN`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,6 +12,7 @@ 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');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
234
src/account-settings/demographics/DemographicsSection.jsx
Normal file
234
src/account-settings/demographics/DemographicsSection.jsx
Normal file
@@ -0,0 +1,234 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import memoize from 'memoize-one';
|
||||
|
||||
import { demographicsSectionSelector } from '../data/selectors';
|
||||
import { saveSettings, updateDraft } from '../data/actions';
|
||||
import EditableField from '../EditableField';
|
||||
import messages from './DemographicsSection.messages';
|
||||
import {
|
||||
SELF_DESCRIBE,
|
||||
DEMOGRAPHICS_GENDER_OPTIONS,
|
||||
DEMOGRAPHICS_ETHNICITY_OPTIONS,
|
||||
DEMOGRAPHICS_INCOME_OPTIONS,
|
||||
DEMOGRAPHICS_MILITARY_HISTORY_OPTIONS,
|
||||
DEMOGRAPHICS_EDUCATION_LEVEL_OPTIONS,
|
||||
DEMOGRAPHICS_WORK_STATUS_OPTIONS,
|
||||
DEMOGRAPHICS_WORK_SECTOR_OPTIONS,
|
||||
DECLINED,
|
||||
} from '../data/constants';
|
||||
|
||||
class DemographicsSection extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
|
||||
this.state = {
|
||||
showSelfDescribe: false
|
||||
}
|
||||
}
|
||||
|
||||
getLocalizedOptions = memoize((locale) => ({
|
||||
demographicsGenderOptions: DEMOGRAPHICS_GENDER_OPTIONS.map(key => ({
|
||||
value: key,
|
||||
label: this.props.intl.formatMessage(messages[`account.settings.field.demographics.gender.options.${key || 'empty'}`]),
|
||||
})).concat(this.getDeclinedOption()),
|
||||
demographicsEthnicityOptions: DEMOGRAPHICS_ETHNICITY_OPTIONS.map(key => ({
|
||||
value: key,
|
||||
label: this.props.intl.formatMessage(messages[`account.settings.field.demographics.ethnicity.options.${key || 'empty'}`]),
|
||||
})).concat(this.getDeclinedOption()),
|
||||
demographicsIncomeOptions: DEMOGRAPHICS_INCOME_OPTIONS.map(key => ({
|
||||
value: key,
|
||||
label: this.props.intl.formatMessage(messages[`account.settings.field.demographics.income.options.${key || 'empty'}`]),
|
||||
})).concat(this.getDeclinedOption()),
|
||||
demographicsMilitaryHistoryOptions: DEMOGRAPHICS_MILITARY_HISTORY_OPTIONS.map(key => ({
|
||||
value: key,
|
||||
label: this.props.intl.formatMessage(messages[`account.settings.field.demographics.military_history.options.${key || 'empty'}`]),
|
||||
})).concat(this.getDeclinedOption()),
|
||||
demographicsEducationLevelOptions: DEMOGRAPHICS_EDUCATION_LEVEL_OPTIONS.map(key => ({
|
||||
value: key,
|
||||
label: this.props.intl.formatMessage(messages[`account.settings.field.demographics.education_level.options.${key || 'empty'}`]),
|
||||
})).concat(this.getDeclinedOption()),
|
||||
demographicsWorkStatusOptions: DEMOGRAPHICS_WORK_STATUS_OPTIONS.map(key => ({
|
||||
value: key,
|
||||
label: this.props.intl.formatMessage(messages[`account.settings.field.demographics.work_status.options.${key || 'empty'}`]),
|
||||
})).concat(this.getDeclinedOption()),
|
||||
demographicsWorkSectorOptions: DEMOGRAPHICS_WORK_SECTOR_OPTIONS.map(key => ({
|
||||
value: key,
|
||||
label: this.props.intl.formatMessage(messages[`account.settings.field.demographics.work_sector.options.${key || 'empty'}`]),
|
||||
})).concat(this.getDeclinedOption()),
|
||||
}));
|
||||
|
||||
getDeclinedOption() {
|
||||
return [{
|
||||
value: DECLINED,
|
||||
label: this.props.intl.formatMessage(messages[`account.settings.field.demographics.options.declined`])
|
||||
}]
|
||||
}
|
||||
|
||||
handleEditableFieldChange = (name, value) => {
|
||||
// Temporary hack until backend hooked up
|
||||
if (name == 'demographics_gender') {
|
||||
let showSelfDescribe = value == SELF_DESCRIBE;
|
||||
this.setState({ showSelfDescribe })
|
||||
}
|
||||
|
||||
this.props.updateDraft(name, value);
|
||||
};
|
||||
|
||||
handleSubmit = (formId, values) => {
|
||||
this.props.saveSettings(formId, values);
|
||||
};
|
||||
|
||||
render() {
|
||||
const editableFieldProps = {
|
||||
onChange: this.handleEditableFieldChange,
|
||||
onSubmit: this.handleSubmit,
|
||||
};
|
||||
|
||||
const {
|
||||
yearOfBirthOptions,
|
||||
demographicsGenderOptions,
|
||||
demographicsEthnicityOptions,
|
||||
demographicsIncomeOptions,
|
||||
demographicsMilitaryHistoryOptions,
|
||||
demographicsEducationLevelOptions,
|
||||
demographicsWorkStatusOptions,
|
||||
demographicsWorkSectorOptions,
|
||||
} = this.getLocalizedOptions(this.context.locale);
|
||||
|
||||
// // TODO: This is what it will be when we have things coming back from the server. Hack for now.
|
||||
// const showSelfDescribe = this.props.formValues.demographics_gender == 'self-describe'
|
||||
|
||||
return (
|
||||
<div className="account-section" id="demographics-information">
|
||||
<h2 className="section-heading">
|
||||
{this.props.intl.formatMessage(messages['account.settings.section.demographics.information'])}
|
||||
</h2>
|
||||
|
||||
<EditableField
|
||||
name="demographics_gender"
|
||||
type="select"
|
||||
value={this.props.formValues.demographics_gender}
|
||||
options={demographicsGenderOptions}
|
||||
label={this.props.intl.formatMessage(messages['account.settings.field.demographics.gender'])}
|
||||
emptyLabel={this.props.intl.formatMessage(messages['account.settings.field.demographics.gender.empty'])}
|
||||
{...editableFieldProps}
|
||||
>
|
||||
<>
|
||||
{this.state.showSelfDescribe && <input />}
|
||||
</>
|
||||
</EditableField>
|
||||
{/* {this.state.showSelfDescribe &&
|
||||
<EditableField
|
||||
name="demographics_gender_description"
|
||||
type="text"
|
||||
value={this.props.formValues.demographics_gender_description}
|
||||
label={this.props.intl.formatMessage(messages['account.settings.field.demographics.gender_description'])}
|
||||
emptyLabel={this.props.intl.formatMessage(messages['account.settings.field.demographics.gender_description.empty'])}
|
||||
{...editableFieldProps}
|
||||
/>
|
||||
} */}
|
||||
<EditableField
|
||||
name="demographics_ethnicity"
|
||||
type="select"
|
||||
value={this.props.formValues.demographics_ethnicity}
|
||||
options={demographicsEthnicityOptions}
|
||||
label={this.props.intl.formatMessage(messages['account.settings.field.demographics.ethnicity'])}
|
||||
emptyLabel={this.props.intl.formatMessage(messages['account.settings.field.demographics.ethnicity.empty'])}
|
||||
{...editableFieldProps}
|
||||
/>
|
||||
<EditableField
|
||||
name="demographics_income"
|
||||
type="select"
|
||||
value={this.props.formValues.demographics_income}
|
||||
options={demographicsIncomeOptions}
|
||||
label={this.props.intl.formatMessage(messages['account.settings.field.demographics.income'])}
|
||||
emptyLabel={this.props.intl.formatMessage(messages['account.settings.field.demographics.income.empty'])}
|
||||
{...editableFieldProps}
|
||||
/>
|
||||
<EditableField
|
||||
name="demographics_military_history"
|
||||
type="select"
|
||||
value={this.props.formValues.demographics_military_history}
|
||||
options={demographicsMilitaryHistoryOptions}
|
||||
label={this.props.intl.formatMessage(messages['account.settings.field.demographics.military_history'])}
|
||||
emptyLabel={this.props.intl.formatMessage(messages['account.settings.field.demographics.military_history.empty'])}
|
||||
{...editableFieldProps}
|
||||
/>
|
||||
<EditableField
|
||||
name="demographics_learner_education_level"
|
||||
type="select"
|
||||
value={this.props.formValues.demographics_learner_education_level}
|
||||
options={demographicsEducationLevelOptions}
|
||||
label={this.props.intl.formatMessage(messages['account.settings.field.demographics.learner_education_level'])}
|
||||
emptyLabel={this.props.intl.formatMessage(messages['account.settings.field.demographics.learner_education_level.empty'])}
|
||||
{...editableFieldProps}
|
||||
/>
|
||||
<EditableField
|
||||
name="demographics_parent_education_level"
|
||||
type="select"
|
||||
value={this.props.formValues.demographics_parent_education_level}
|
||||
options={demographicsEducationLevelOptions}
|
||||
label={this.props.intl.formatMessage(messages['account.settings.field.demographics.parent_education_level'])}
|
||||
emptyLabel={this.props.intl.formatMessage(messages['account.settings.field.demographics.parent_education_level.empty'])}
|
||||
{...editableFieldProps}
|
||||
/>
|
||||
<EditableField
|
||||
name="demographics_work_status"
|
||||
type="select"
|
||||
value={this.props.formValues.demographics_work_status}
|
||||
options={demographicsWorkStatusOptions}
|
||||
label={this.props.intl.formatMessage(messages['account.settings.field.demographics.work_status'])}
|
||||
emptyLabel={this.props.intl.formatMessage(messages['account.settings.field.demographics.work_status.empty'])}
|
||||
{...editableFieldProps}
|
||||
/>
|
||||
<EditableField
|
||||
name="demographics_current_work_sector"
|
||||
type="select"
|
||||
value={this.props.formValues.demographics_current_work_sector}
|
||||
options={demographicsWorkSectorOptions}
|
||||
label={this.props.intl.formatMessage(messages['account.settings.field.demographics.current_work_sector'])}
|
||||
emptyLabel={this.props.intl.formatMessage(messages['account.settings.field.demographics.current_work_sector.empty'])}
|
||||
{...editableFieldProps}
|
||||
/>
|
||||
<EditableField
|
||||
name="demographics_future_work_sector"
|
||||
type="select"
|
||||
value={this.props.formValues.demographics_future_work_sector}
|
||||
options={demographicsWorkSectorOptions}
|
||||
label={this.props.intl.formatMessage(messages['account.settings.field.demographics.future_work_sector'])}
|
||||
emptyLabel={this.props.intl.formatMessage(messages['account.settings.field.demographics.future_work_sector.empty'])}
|
||||
{...editableFieldProps}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
DemographicsSection.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
formValues: PropTypes.shape({
|
||||
demographics_gender: PropTypes.string,
|
||||
demographics_ethnicity: PropTypes.string,
|
||||
demographics_income: PropTypes.string,
|
||||
demographics_military_history: PropTypes.string,
|
||||
demographics_learner_education_level: PropTypes.string,
|
||||
demographics_parent_education_level: PropTypes.string,
|
||||
demographics_work_status: PropTypes.string,
|
||||
demographics_current_work_sector: PropTypes.string,
|
||||
demographics_future_work_sector: PropTypes.string,
|
||||
}).isRequired,
|
||||
saveSettings: PropTypes.func.isRequired,
|
||||
updateDraft: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
// DemographicsSection.defaultProps = {
|
||||
//
|
||||
// };
|
||||
|
||||
export default connect(demographicsSectionSelector, {
|
||||
saveSettings,
|
||||
updateDraft,
|
||||
})(injectIntl(DemographicsSection))
|
||||
@@ -0,0 +1,446 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
'account.settings.section.demographics.information': {
|
||||
id: 'account.settings.section.demographics.information',
|
||||
defaultMessage: 'Optional Information',
|
||||
description: 'The optional information section heading.',
|
||||
},
|
||||
'account.settings.field.demographics.gender': {
|
||||
id: 'account.settings.field.demographics.gender',
|
||||
defaultMessage: 'Gender identity',
|
||||
description: 'Label for account settings gender identity field.',
|
||||
},
|
||||
'account.settings.field.demographics.gender.empty': {
|
||||
id: 'account.settings.field.demographics.gender.empty',
|
||||
defaultMessage: 'Add gender identity',
|
||||
description: 'Placeholder for empty account settings gender identity field.',
|
||||
},
|
||||
'account.settings.field.demographics.gender.options.empty': {
|
||||
id: 'account.settings.field.demographics.gender.options.empty',
|
||||
defaultMessage: 'Select a gender identity',
|
||||
description: 'Placeholder for the gender identity options dropdown.',
|
||||
},
|
||||
'account.settings.field.demographics.gender.options.woman': {
|
||||
id: 'account.settings.field.demographics.gender.options.woman',
|
||||
defaultMessage: 'Woman',
|
||||
description: 'The label for the woman gender identity option.',
|
||||
},
|
||||
'account.settings.field.demographics.gender.options.man': {
|
||||
id: 'account.settings.field.demographics.gender.options.man',
|
||||
defaultMessage: 'Man',
|
||||
description: 'The label for the man gender identity option.',
|
||||
},
|
||||
'account.settings.field.demographics.gender.options.non-binary': {
|
||||
id: 'account.settings.field.demographics.gender.options.non-binary',
|
||||
defaultMessage: 'Non-binary',
|
||||
description: 'The label for the non-binary gender identity option.',
|
||||
},
|
||||
'account.settings.field.demographics.gender.options.self-describe': {
|
||||
id: 'account.settings.field.demographics.gender.options.self-describe',
|
||||
defaultMessage: 'Prefer to self-describe',
|
||||
description: 'The label for self-describe gender identity option.',
|
||||
},
|
||||
'account.settings.field.demographics.gender_description': {
|
||||
id: 'account.settings.field.demographics.gender_description',
|
||||
defaultMessage: 'Gender identity description',
|
||||
description: 'Label for account settings gender identity description field.',
|
||||
},
|
||||
'account.settings.field.demographics.gender_description.empty': {
|
||||
id: 'account.settings.field.demographics.gender_description.empty',
|
||||
defaultMessage: 'Add gender identity description',
|
||||
description: 'Placeholder for empty account settings gender identity field.',
|
||||
},
|
||||
'account.settings.field.demographics.ethnicity': {
|
||||
id: 'account.settings.field.demographics.ethnicity',
|
||||
defaultMessage: 'Ethnic background',
|
||||
description: 'Label for account settings ethnic background field.',
|
||||
},
|
||||
'account.settings.field.demographics.ethnicity.empty': {
|
||||
id: 'account.settings.field.demographics.ethnicity.empty',
|
||||
defaultMessage: 'Add ethnic background',
|
||||
description: 'Placeholder for empty account settings ethnic background field.',
|
||||
},
|
||||
'account.settings.field.demographics.ethnicity.options.empty': {
|
||||
id: 'account.settings.field.demographics.ethnicity.options.empty',
|
||||
defaultMessage: 'Select all that apply', // TODO: Is this the desired text?
|
||||
description: 'Placeholder for the ethnic background options field.',
|
||||
},
|
||||
'account.settings.field.demographics.ethnicity.options.american-indian-or-alaska-native': {
|
||||
id: 'account.settings.field.demographics.ethnicity.options.american-indian-or-alaska-native',
|
||||
defaultMessage: 'American Indian or Alaska Native',
|
||||
description: 'The label for the American Indian or Alaska Native ethnicity option.',
|
||||
},
|
||||
'account.settings.field.demographics.ethnicity.options.asian': {
|
||||
id: 'account.settings.field.demographics.ethnicity.options.asian',
|
||||
defaultMessage: 'Asian',
|
||||
description: 'The label for the Asian ethnicity option.',
|
||||
},
|
||||
'account.settings.field.demographics.ethnicity.options.black-or-african-american': {
|
||||
id: 'account.settings.field.demographics.ethnicity.options.black-or-african-american',
|
||||
defaultMessage: 'Black or African American',
|
||||
description: 'The label for the Black or African American ethnicity option.',
|
||||
},
|
||||
'account.settings.field.demographics.ethnicity.options.hispanic-latin-spanish': {
|
||||
id: 'account.settings.field.demographics.ethnicity.options.hispanic-latin-spanish',
|
||||
defaultMessage: 'Hispanic, Latin, or Spanish origin',
|
||||
description: 'The label for the Hispanic, Latin, or Spanish origin ethnicity option.',
|
||||
},
|
||||
'account.settings.field.demographics.ethnicity.options.middle-eastern-or-north-african': {
|
||||
id: 'account.settings.field.demographics.ethnicity.options.middle-eastern-or-north-african',
|
||||
defaultMessage: 'Middle Eastern or North African',
|
||||
description: 'The label for the Middle Eastern or North African ethnicity option.',
|
||||
},
|
||||
'account.settings.field.demographics.ethnicity.options.native-hawaiian-or-pacific-islander': {
|
||||
id: 'account.settings.field.demographics.ethnicity.options.native-hawaiian-or-pacific-islander',
|
||||
defaultMessage: 'Native Hawaiian or Other Pacific Islander',
|
||||
description: 'The label for the Native Hawaiian or Other Pacific Islander ethnicity option.',
|
||||
},
|
||||
'account.settings.field.demographics.ethnicity.options.white': {
|
||||
id: 'account.settings.field.demographics.ethnicity.options.white',
|
||||
defaultMessage: 'White',
|
||||
description: 'The label for the White ethnicity option.',
|
||||
},
|
||||
'account.settings.field.demographics.ethnicity.options.other': {
|
||||
id: 'account.settings.field.demographics.ethnicity.options.other',
|
||||
defaultMessage: 'Some other race, ethnicity, or origin',
|
||||
description: 'The label for the Some other race, ethnicity, or origin ethnicity option.',
|
||||
},
|
||||
'account.settings.field.demographics.income': {
|
||||
id: 'account.settings.field.demographics.income',
|
||||
defaultMessage: 'Household income',
|
||||
description: 'Label for account settings household income field.',
|
||||
},
|
||||
'account.settings.field.demographics.income.empty': {
|
||||
id: 'account.settings.field.demographics.income.empty',
|
||||
defaultMessage: 'Add household income',
|
||||
description: 'Placeholder for empty account settings household income field.',
|
||||
},
|
||||
'account.settings.field.demographics.income.options.empty': {
|
||||
id: 'account.settings.field.demographics.income.options.empty',
|
||||
defaultMessage: 'Select a household income range',
|
||||
description: 'Placeholder for the household income dropdown.',
|
||||
},
|
||||
'account.settings.field.demographics.income.options.less-than-10k': {
|
||||
id: 'account.settings.field.demographics.income.options.less-than-10k',
|
||||
defaultMessage: 'Less than US $10,000',
|
||||
description: 'The label for the less than US $10,000 income option.',
|
||||
},
|
||||
'account.settings.field.demographics.income.options.10k-25k': {
|
||||
id: 'account.settings.field.demographics.income.options.10k-25k',
|
||||
defaultMessage: 'US $10,000 - $25,000',
|
||||
description: 'The label for the US $10,000 - $25,000 income option.',
|
||||
},
|
||||
'account.settings.field.demographics.income.options.25k-50k': {
|
||||
id: 'account.settings.field.demographics.income.options.25k-50k',
|
||||
defaultMessage: 'US $25,000 - $50,000',
|
||||
description: 'The label for the US $25,000 - $50,000 income option.',
|
||||
},
|
||||
'account.settings.field.demographics.income.options.50k-75k': {
|
||||
id: 'account.settings.field.demographics.income.options.50k-75k',
|
||||
defaultMessage: 'US $50,000 - $75,000',
|
||||
description: 'The label for the US $50,000 - $75,000 income option.',
|
||||
},
|
||||
'account.settings.field.demographics.income.options.over-100k': {
|
||||
id: 'account.settings.field.demographics.income.options.over-100k',
|
||||
defaultMessage: 'Over US $100,000',
|
||||
description: 'The label for the over US $100,000 income option.',
|
||||
},
|
||||
'account.settings.field.demographics.income.options.unsure': {
|
||||
id: 'account.settings.field.demographics.income.options.unsure',
|
||||
defaultMessage: 'I don\'t know',
|
||||
description: 'The label for the I don\'t know income option.',
|
||||
},
|
||||
'account.settings.field.demographics.military_history': {
|
||||
id: 'account.settings.field.demographics.military_history',
|
||||
defaultMessage: 'US Armed Forces service',
|
||||
description: 'Label for account settings military history field.',
|
||||
},
|
||||
'account.settings.field.demographics.military_history.empty': {
|
||||
id: 'account.settings.field.demographics.military_history.empty',
|
||||
defaultMessage: 'Add military history',
|
||||
description: 'Placeholder for empty account settings military history field.',
|
||||
},
|
||||
'account.settings.field.demographics.military_history.options.empty': {
|
||||
id: 'account.settings.field.demographics.military_history.options.empty',
|
||||
defaultMessage: 'Select military history',
|
||||
description: 'Placeholder for the military history dropdown.',
|
||||
},
|
||||
'account.settings.field.demographics.military_history.options.never-served': {
|
||||
id: 'account.settings.field.demographics.income.options.never-served',
|
||||
defaultMessage: 'Never served in the military',
|
||||
description: 'The label for the never served in the military military history option.',
|
||||
},
|
||||
'account.settings.field.demographics.military_history.options.training': {
|
||||
id: 'account.settings.field.demographics.income.options.training',
|
||||
defaultMessage: 'Only on active duty for training',
|
||||
description: 'The label for the only on active duty for training military history option.',
|
||||
},
|
||||
'account.settings.field.demographics.military_history.options.active': {
|
||||
id: 'account.settings.field.demographics.income.options.active',
|
||||
defaultMessage: 'Now on active duty',
|
||||
description: 'The label for the now on active duty military history option.',
|
||||
},
|
||||
'account.settings.field.demographics.military_history.options.previously-active': {
|
||||
id: 'account.settings.field.demographics.income.options.previously-active',
|
||||
defaultMessage: 'On active duty in the past, but not now',
|
||||
description: 'The label for the on active duty in the past, but not now military history option.',
|
||||
},
|
||||
'account.settings.field.demographics.learner_education_level': {
|
||||
id: 'account.settings.field.demographics.learner_education_level',
|
||||
defaultMessage: 'Highest level of education',
|
||||
description: 'Label for account settings learner education level field.',
|
||||
},
|
||||
'account.settings.field.demographics.learner_education_level.empty': {
|
||||
id: 'account.settings.field.demographics.learner_education_level.empty',
|
||||
defaultMessage: 'Add education level',
|
||||
description: 'Placeholder for empty account settings learner education level field.',
|
||||
},
|
||||
'account.settings.field.demographics.parent_education_level': {
|
||||
id: 'account.settings.field.demographics.parent_education_level',
|
||||
defaultMessage: 'Highest level of education of a parent or guardian',
|
||||
description: 'Label for account settings parent education level field.',
|
||||
},
|
||||
'account.settings.field.demographics.parent_education_level.empty': {
|
||||
id: 'account.settings.field.demographics.parent_education_level.empty',
|
||||
defaultMessage: 'Add education level',
|
||||
description: 'Placeholder for empty account settings parent education level field.',
|
||||
},
|
||||
'account.settings.field.demographics.education_level.options.empty': {
|
||||
id: 'account.settings.field.demographics.education_level.options.empty',
|
||||
defaultMessage: 'Select an education level',
|
||||
description: 'Placeholder for the education level options dropdown.',
|
||||
},
|
||||
'account.settings.field.demographics.education_level.options.no-high-school': {
|
||||
id: 'account.settings.field.demographics.education_level.options.no-high-school',
|
||||
defaultMessage: 'No High School',
|
||||
description: 'The label for the no high school education level option.',
|
||||
},
|
||||
'account.settings.field.demographics.education_level.options.some-high-school': {
|
||||
id: 'account.settings.field.demographics.education_level.options.some-high-school',
|
||||
defaultMessage: 'Some High School',
|
||||
description: 'The label for the some high school education level option.',
|
||||
},
|
||||
'account.settings.field.demographics.education_level.options.high-school-ged-equivalent': {
|
||||
id: 'account.settings.field.demographics.education_level.options.high-school-ged-equivalent',
|
||||
defaultMessage: 'High School diploma, GED, or equivalent',
|
||||
description: 'The label for the high school diploma, GED, or equivalent education level option.',
|
||||
},
|
||||
'account.settings.field.demographics.education_level.options.some-college': {
|
||||
id: 'account.settings.field.demographics.education_level.options.some-college',
|
||||
defaultMessage: 'Some college, but no degree',
|
||||
description: 'The label for the some college, but no degree education level option.',
|
||||
},
|
||||
'account.settings.field.demographics.education_level.options.some-college': {
|
||||
id: 'account.settings.field.demographics.education_level.options.some-college',
|
||||
defaultMessage: 'Some college, but no degree',
|
||||
description: 'The label for the some college, but no degree education level option.',
|
||||
},
|
||||
'account.settings.field.demographics.education_level.options.associates': {
|
||||
id: 'account.settings.field.demographics.education_level.options.associates',
|
||||
defaultMessage: 'Associates degree',
|
||||
description: 'The label for the Associates degree education level option.',
|
||||
},
|
||||
'account.settings.field.demographics.education_level.options.bachelors': {
|
||||
id: 'account.settings.field.demographics.education_level.options.bachelors',
|
||||
defaultMessage: 'Bachelors degree',
|
||||
description: 'The label for the Bachelors degree education level option.',
|
||||
},
|
||||
'account.settings.field.demographics.education_level.options.masters': {
|
||||
id: 'account.settings.field.demographics.education_level.options.masters',
|
||||
defaultMessage: 'Masters degree',
|
||||
description: 'The label for the Masters degree education level option.',
|
||||
},
|
||||
'account.settings.field.demographics.education_level.options.professional': {
|
||||
id: 'account.settings.field.demographics.education_level.options.professional',
|
||||
defaultMessage: 'Professional degree',
|
||||
description: 'The label for the Professional degree education level option.',
|
||||
},
|
||||
'account.settings.field.demographics.education_level.options.doctorate': {
|
||||
id: 'account.settings.field.demographics.education_level.options.doctorate',
|
||||
defaultMessage: 'Doctorate degree',
|
||||
description: 'The label for the Doctorate degree education level option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_status': {
|
||||
id: 'account.settings.field.demographics.work_status',
|
||||
defaultMessage: 'Current work status',
|
||||
description: 'Label for account settings work status field.',
|
||||
},
|
||||
'account.settings.field.demographics.work_status.empty': {
|
||||
id: 'account.settings.field.demographics.work_status.empty',
|
||||
defaultMessage: 'Add work status',
|
||||
description: 'Placeholder for empty account settings work status field.',
|
||||
},
|
||||
'account.settings.field.demographics.work_status.options.empty': {
|
||||
id: 'account.settings.field.demographics.work_status.options.empty',
|
||||
defaultMessage: 'Select a work status',
|
||||
description: 'Placeholder for the work status options dropdown.',
|
||||
},
|
||||
'account.settings.field.demographics.work_status.options.full-time': {
|
||||
id: 'account.settings.field.demographics.work_status.options.full-time',
|
||||
defaultMessage: 'Employed, working full-time',
|
||||
description: 'The label for the employed, working full-time work status option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_status.options.part-time': {
|
||||
id: 'account.settings.field.demographics.work_status.options.part-time',
|
||||
defaultMessage: 'Employed, working part-time',
|
||||
description: 'The label for the employed, working part-time work status option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_status.options.not-employed-looking': {
|
||||
id: 'account.settings.field.demographics.work_status.options.not-employed-looking',
|
||||
defaultMessage: 'Not employed, looking for work',
|
||||
description: 'The label for the not employed, looking for work work status option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_status.options.not-employed-not-looking': {
|
||||
id: 'account.settings.field.demographics.work_status.options.not-employed-not-looking',
|
||||
defaultMessage: 'Not employed, not looking for work',
|
||||
description: 'The label for the not employed, not looking for work work status option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_status.options.unable': {
|
||||
id: 'account.settings.field.demographics.work_status.options.unable',
|
||||
defaultMessage: 'Unable to work',
|
||||
description: 'The label for the unable to work work status option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_status.options.retired': {
|
||||
id: 'account.settings.field.demographics.work_status.options.retired',
|
||||
defaultMessage: 'Retired',
|
||||
description: 'The label for the retired work status option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_status.options.other': {
|
||||
id: 'account.settings.field.demographics.work_status.options.other',
|
||||
defaultMessage: 'Other',
|
||||
description: 'The label for the other work status option.',
|
||||
},
|
||||
'account.settings.field.demographics.current_work_sector': {
|
||||
id: 'account.settings.field.demographics.current_work_sector',
|
||||
defaultMessage: 'Current indstry',
|
||||
description: 'Label for account settings current work sector field.',
|
||||
},
|
||||
'account.settings.field.demographics.current_work_sector.empty': {
|
||||
id: 'account.settings.field.demographics.current_work_sector.empty',
|
||||
defaultMessage: 'Add industry',
|
||||
description: 'Placeholder for empty account settings current work sector field.',
|
||||
},
|
||||
'account.settings.field.demographics.future_work_sector': {
|
||||
id: 'account.settings.field.demographics.future_work_sector',
|
||||
defaultMessage: 'Future industry',
|
||||
description: 'Label for account settings future work sector field.',
|
||||
},
|
||||
'account.settings.field.demographics.future_work_sector.empty': {
|
||||
id: 'account.settings.field.demographics.future_work_sector.empty',
|
||||
defaultMessage: 'Add industry',
|
||||
description: 'Placeholder for empty account settings future work sector field.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.empty': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.empty',
|
||||
defaultMessage: 'Select an industry',
|
||||
description: 'Placeholder for the work sector options dropdown.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.accommodation-food': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.accommodation-food',
|
||||
defaultMessage: 'Accommodation and Food Services',
|
||||
description: 'The label for the Accommodation and Food Services work sector option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.administrative-support-waste-remediation': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.administrative-support-waste-remediation',
|
||||
defaultMessage: 'Administrative and Support and Waste Management and Remediation Services',
|
||||
description: 'The label for the Administrative and Support and Waste Management and Remediation Services work sector option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.agriculture-forestry-fishing-hunting': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.agriculture-forestry-fishing-hunting',
|
||||
defaultMessage: 'Agriculture, Forestry, Fishing and Hunting',
|
||||
description: 'The label for the Agriculture, Forestry, Fishing and Hunting work sector option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.arts-entertainment-recreation': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.arts-entertainment-recreation',
|
||||
defaultMessage: 'Arts, Entertainment, and Recreation',
|
||||
description: 'The label for the Arts, Entertainment, and Recreation work sector option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.construction': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.construction',
|
||||
defaultMessage: 'Construction',
|
||||
description: 'The label for the Construction work sector option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.educational': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.educational',
|
||||
defaultMessage: 'Education Services',
|
||||
description: 'The label for the Education Services work sector option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.finance-insurance': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.finance-insurance',
|
||||
defaultMessage: 'Finance and Insurance',
|
||||
description: 'The label for the Finance and Insurance work sector option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.healthcare-social': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.healthcare-social',
|
||||
defaultMessage: 'Health Care and Social Assistance',
|
||||
description: 'The label for the Health Care and Social Assistance work sector option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.information': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.information',
|
||||
defaultMessage: 'Information',
|
||||
description: 'The label for the Information work sector option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.management': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.management',
|
||||
defaultMessage: 'Management of Companies and Enterprises',
|
||||
description: 'The label for the Management of Companies and Enterprises work sector option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.manufacturing': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.manufacturing',
|
||||
defaultMessage: 'Manufacturing',
|
||||
description: 'The label for the Manufacturing work sector option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.mining-quarry-oil-gas': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.mining-quarry-oil-gas',
|
||||
defaultMessage: 'Mining, Quarrying, and Oil and Gas Extraction',
|
||||
description: 'The label for the Mining, Quarrying, and Oil and Gas Extraction work sector option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.professional-scientific-technical': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.professional-scientific-technical',
|
||||
defaultMessage: 'Professional, Scientific, and Technical Services',
|
||||
description: 'The label for the Professional, Scientific, and Technical Services work sector option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.public-admin': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.public-admin',
|
||||
defaultMessage: 'Public Administration',
|
||||
description: 'The label for the Public Administration work sector option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.real-estate': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.real-estate',
|
||||
defaultMessage: 'Real Estate and Rental and Leasing',
|
||||
description: 'The label for the Real Estate and Rental and Leasing work sector option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.retail': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.retail',
|
||||
defaultMessage: 'Retail Trade',
|
||||
description: 'The label for the Retail Trade work sector option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.transport-warehousing': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.transport-warehousing',
|
||||
defaultMessage: 'Transportation and Warehousing',
|
||||
description: 'The label for the Transportation and Warehousing work sector option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.utilities': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.utilities',
|
||||
defaultMessage: 'Utilities',
|
||||
description: 'The label for the Utilities work sector option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.trade': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.trade',
|
||||
defaultMessage: 'Wholesale Trade',
|
||||
description: 'The label for the Wholesale Trade work sector option.',
|
||||
},
|
||||
'account.settings.field.demographics.work_sector.options.other': {
|
||||
id: 'account.settings.field.demographics.work_sector.options.other',
|
||||
defaultMessage: 'Other',
|
||||
description: 'The label for the Other work sector option.',
|
||||
},
|
||||
'account.settings.field.demographics.options.declined': {
|
||||
id: 'account.settings.field.demographics.options.declined',
|
||||
defaultMessage: 'Prefer not to respond',
|
||||
description: 'The label for the declined option.',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
@@ -0,0 +1,24 @@
|
||||
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;
|
||||
@@ -7,6 +7,7 @@ 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;
|
||||
@@ -43,6 +44,7 @@ const ResetPassword = (props) => {
|
||||
/>
|
||||
</p>
|
||||
{status === 'complete' ? <ConfirmationAlert email={email} /> : null}
|
||||
{status === 'forbidden' ? <RequestInProgressAlert /> : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -18,3 +18,7 @@ export const resetPasswordSuccess = () => ({
|
||||
export const resetPasswordReset = () => ({
|
||||
type: RESET_PASSWORD.RESET,
|
||||
});
|
||||
|
||||
export const resetPasswordForbidden = () => ({
|
||||
type: RESET_PASSWORD.FORBIDDEN,
|
||||
});
|
||||
|
||||
@@ -17,6 +17,11 @@ const reducer = (state = defaultState, action = null) => {
|
||||
...state,
|
||||
status: 'complete',
|
||||
};
|
||||
case RESET_PASSWORD.FORBIDDEN:
|
||||
return {
|
||||
...state,
|
||||
status: 'forbidden',
|
||||
};
|
||||
|
||||
default:
|
||||
}
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
import { put, call, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import { resetPasswordBegin, resetPasswordSuccess, RESET_PASSWORD } from './actions';
|
||||
import { resetPasswordBegin, resetPasswordForbidden, resetPasswordSuccess, RESET_PASSWORD } from './actions';
|
||||
import { postResetPassword } from './service';
|
||||
|
||||
function* handleResetPassword(action) {
|
||||
yield put(resetPasswordBegin());
|
||||
const response = yield call(postResetPassword, action.payload.email);
|
||||
yield put(resetPasswordSuccess(response));
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default function* saga() {
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
"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",
|
||||
@@ -87,10 +90,12 @@
|
||||
"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 in English and Spanish languages. 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 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.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",
|
||||
@@ -120,6 +125,7 @@
|
||||
"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",
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
"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": "Añada un estado",
|
||||
"account.settings.field.state.options.empty": "Seleccionar un estado",
|
||||
"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",
|
||||
@@ -74,24 +77,26 @@
|
||||
"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 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": "Let’s 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 you’re 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.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 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.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": "Empecemos",
|
||||
"account.settings.coaching.consent.welcome.subheader": "Estamos aquí para ustede desde el inicio hasta el final",
|
||||
"account.settings.coaching.consent.description": "Los programas de MicroBachelors incluyen entrenamiento que se enfoca en su carrera, educación y cómo logrará resultados a través de la comunicación individual con un profesional experimentado. Si está interesado, proporcione la información a continuación y haga clic en \"Enviar\", y nuestro socio asesor se comunicará con usted por correo electrónico y / o mensaje de texto para ayudarlo a avanzar. Los términos y Condiciones aplican.*",
|
||||
"account.settings.coaching.consent.text-messaging.disclaimer": "* Los servicios de entrenamiento se incluyen sin costo adicional para los alumnos con números de teléfono de EE. UU. El entrenamiento incluye mensajes de texto recurrentes. Se pueden aplicar tarifas por mensajes y datos. Envía STOP para cancelar la suscripción.",
|
||||
"account.settings.coaching.consent.accept-coaching": "Registrarse para coaching",
|
||||
"account.settings.coaching.consent.decline-coaching": "Prefiero no ser contactado con servicios de coaching gratuitos.",
|
||||
"account.settings.coaching.consent.label.name": "Por favor confirme su nombre",
|
||||
"account.settings.coaching.consent.label.phone-number": "Ingrese su número de teléfono móvil",
|
||||
"account.settings.coaching.consent.success.header": "¡Éxito!",
|
||||
"account.settings.coaching.consent.success.message": "Estás registrado para coaching. Recibirá un mensaje de texto de confirmación.",
|
||||
"account.settings.coaching.consent.success.continue": "Iniciar mi curso",
|
||||
"account.settings.coaching.managed.support": "soporte",
|
||||
"account.settings.coaching.managed.alert": "{ManagerTitle} administra su Nombre. Póngase en contacto con su administrador para obtener ayuda.",
|
||||
"account.settings.field.phone_number": "Teléfono",
|
||||
"account.settings.field.phone_number.empty": "Añadir un número de teléfono",
|
||||
"account.settings.field.coaching_consent": "Consentimiento de coaching",
|
||||
"account.settings.field.coaching_consent.tooltip": "Los programas de MicroBachelors incluyen entrenamiento basado en mensajes de texto que lo ayuda a emparejar experiencias educativas con sus objetivos profesionales a través de asesoramiento personalizado. Los servicios de entrenamiento se incluyen sin costo adicional y están disponibles para estudiantes con números de teléfono móvil de EE. UU. Se aplican tarifas de mensajería estándar. Envíe \"STOP\" en cualquier momento para cancelar la suscripción a los mensajes.",
|
||||
"account.settings.field.coaching_consent.error": "Se requiere un número de teléfono válido de EE. UU. Para optar por el coaching",
|
||||
"account.settings.delete.account.before.proceeding": "Antes de continuar, por favor {actionLink}.",
|
||||
"account.settings.delete.account.header": "Eliminar mi cuenta",
|
||||
"account.settings.delete.account.subheader": "¡Sentimos que te vayas!",
|
||||
@@ -102,7 +107,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": "unlink all social media accounts",
|
||||
"account.settings.delete.account.please.unlink": "Desvincular todas las cuentas de redes sociales.",
|
||||
"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.",
|
||||
@@ -120,10 +125,11 @@
|
||||
"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": "Su solicitud anterior está en progreso, intente nuevamente en unos momentos.",
|
||||
"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": "There was a problem disconnecting this account. Contact support if the problem persists.",
|
||||
"account.settings.sso.account.disconnect.error": "Hubo un problema al desconectar esta Cuenta. Si el problema persiste, contacte soporte.",
|
||||
"account.settings.sso.unlink.account": "Desvincular la cuenta de {accountName} ",
|
||||
"account.settings.sso.no.providers": "No accounts can be linked at this time."
|
||||
"account.settings.sso.no.providers": "No se pueden vincular cuentas en este momento."
|
||||
}
|
||||
@@ -33,6 +33,9 @@
|
||||
"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",
|
||||
@@ -87,10 +90,12 @@
|
||||
"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 in English and Spanish languages. 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 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.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",
|
||||
@@ -120,6 +125,7 @@
|
||||
"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",
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
"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",
|
||||
@@ -87,10 +90,12 @@
|
||||
"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 in English and Spanish languages. 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 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.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",
|
||||
@@ -120,6 +125,7 @@
|
||||
"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",
|
||||
|
||||
Reference in New Issue
Block a user