Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions src/actions/loadUser.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {
ACCOUNTS_APP_CONNECTOR_URL,
LOAD_USER_SUCCESS,
LOAD_USER_FAILURE,
LOAD_USER_CREDENTIAL,
LOAD_USER_CREDENTIAL_FAILURE,
LOAD_ORG_CONFIG_SUCCESS,
LOAD_ORG_CONFIG_FAILURE,
ROLE_ADMINISTRATOR,
Expand All @@ -16,7 +18,7 @@ import {
ROLE_PRESALES, ROLE_PROJECT_MANAGER, ROLE_SOLUTION_ARCHITECT
} from '../config/constants'
import { getFreshToken, configureConnector, decodeToken } from 'tc-auth-lib'
import { getUserProfile } from '../api/users'
import { getUserProfile, getCredential } from '../api/users'
import { fetchGroups } from '../api/groups'
import { getOrgConfig } from '../api/orgConfig'
import { EventTypes } from 'redux-segment'
Expand All @@ -26,6 +28,18 @@ configureConnector({
frameId: 'tc-accounts-iframe'
})

export function getUserCredential(userId) {
return (dispatch) => {
return dispatch({
type: LOAD_USER_CREDENTIAL,
payload: getCredential(userId)
}).catch((err) => {
console.log(err)
dispatch({ type: LOAD_USER_CREDENTIAL_FAILURE })
})
}
}

export function loadUser() {
return ((dispatch, getState) => {
const state = getState()
Expand Down Expand Up @@ -125,9 +139,9 @@ export function loadUserSuccess(dispatch, token) {
loadGroups(dispatch, currentUser.userId)
})
.catch((err) => {
// if we fail to load user's profile, still dispatch user load success
// ideally it shouldn't happen, but if it is, we can render the page
// without profile information
// if we fail to load user's profile, still dispatch user load success
// ideally it shouldn't happen, but if it is, we can render the page
// without profile information
console.log(err)
dispatch({ type: LOAD_USER_SUCCESS, user : currentUser })
})
Expand Down Expand Up @@ -161,7 +175,7 @@ function loadGroups(dispatch, userId) {
}
})
.catch((err) => {
// if we fail to load groups
// if we fail to load groups
console.log(err)
})
}
Expand Down
17 changes: 17 additions & 0 deletions src/api/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,23 @@ export function getUserProfile(handle) {
})
}


/**
* Gets credential for the specified user id.
*
* NOTE: Only admins are authorized to use the underlying endpoint.
*
* @param {Number} userId The user id
* @return {Promise} Resolves to the linked accounts array.
*/
export function getCredential(userId) {
return axios.get(`${TC_API_URL}/v3/users/${userId}?fields=credential`)
.then(resp => {
return _.get(resp.data, 'result.content', {})
})
}


/**
* Update user profile
*
Expand Down
6 changes: 6 additions & 0 deletions src/config/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ import { getCookie } from '../helpers/cookie'
export const LOAD_USER_SUCCESS = 'LOAD_USER_SUCCESS'
export const LOAD_USER_FAILURE = 'LOAD_USER_FAILURE'

export const LOAD_USER_CREDENTIAL = 'LOAD_USER_CREDENTIAL'
export const LOAD_USER_CREDENTIAL_PENDING = 'LOAD_USER_CREDENTIAL_PENDING'
export const LOAD_USER_CREDENTIAL_SUCCESS = 'LOAD_USER_CREDENTIAL_SUCCESS'
export const LOAD_USER_CREDENTIAL_FAILURE = 'LOAD_USER_CREDENTIAL_FAILURE'


// Load organization configs
export const LOAD_ORG_CONFIG_SUCCESS = 'LOAD_ORG_CONFIG_SUCCESS'
export const LOAD_ORG_CONFIG_FAILURE = 'LOAD_ORG_CONFIG_FAILURE'
Expand Down
16 changes: 16 additions & 0 deletions src/reducers/loadUser.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import _ from 'lodash'
import {
LOAD_USER_SUCCESS,
LOAD_USER_FAILURE,
LOAD_USER_CREDENTIAL_PENDING,
LOAD_USER_CREDENTIAL_SUCCESS,
LOAD_USER_CREDENTIAL_FAILURE,
LOAD_ORG_CONFIG_SUCCESS,
LOAD_ORG_CONFIG_FAILURE,
SAVE_PROFILE_PHOTO_SUCCESS,
Expand All @@ -18,6 +21,19 @@ export const initialState = {
export default function(state = initialState, action) {
switch (action.type) {

case LOAD_USER_CREDENTIAL_PENDING:
return Object.assign({}, state, {
isLoadingCredential: true,
})
case LOAD_USER_CREDENTIAL_SUCCESS:
return Object.assign({}, state, {
isLoadingCredential: false,
credential: action.payload.credential
})
case LOAD_USER_CREDENTIAL_FAILURE:
return Object.assign({}, state, {
isLoadingCredential: false,
})
case LOAD_USER_SUCCESS:
return Object.assign({}, state, {
isLoading : false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class ChangeEmailForm extends React.Component {
}

render() {
const { settings, checkingEmail, checkedEmail, isEmailAvailable, isEmailChanging, emailSubmitted} = this.props
const {usingSsoService, settings, checkingEmail, checkedEmail, isEmailAvailable, isEmailChanging, emailSubmitted} = this.props
const { currentEmail, isValid, isFocused } = this.state
const currentEmailAvailable = checkedEmail === currentEmail && isEmailAvailable
const isCheckingCurrentEmail = checkingEmail === currentEmail
Expand Down Expand Up @@ -140,7 +140,7 @@ class ChangeEmailForm extends React.Component {
validationErrors={{
isEmail: 'Provide a correct email'
}}
disabled={isEmailChanging || !hasPermission(PERMISSIONS.UPDATE_USER_EMAIL)}
disabled={usingSsoService || isEmailChanging || !hasPermission(PERMISSIONS.UPDATE_USER_EMAIL)}
ref={(ref) => this.emailRef = ref}
/>
{ isFocused && isCheckingCurrentEmail && (
Expand Down Expand Up @@ -174,6 +174,7 @@ class ChangeEmailForm extends React.Component {

ChangeEmailForm.propTypes = {
email: PropTypes.string,
usingSsoService: PropTypes.bool,
onSubmit: PropTypes.func.isRequired,
checkingEmail: PropTypes.string,
checkedEmail: PropTypes.string,
Expand Down
33 changes: 23 additions & 10 deletions src/routes/settings/routes/system/components/SystemSettingsForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const TCFormFields = FormsyForm.Fields

class SystemSettingsForm extends Component {
render() {
const { changePassword, checkEmailAvailability, changeEmail, systemSettings, resetPassword } = this.props
const { changePassword, checkEmailAvailability, changeEmail, systemSettings, resetPassword, usingSsoService } = this.props
return (
<div styleName="system-settings-container">

Expand Down Expand Up @@ -40,20 +40,33 @@ class SystemSettingsForm extends Component {
checkEmailAvailability={checkEmailAvailability}
onSubmit={(email) => changeEmail(email)}
{...systemSettings}
usingSsoService={usingSsoService}
/>

{usingSsoService && (
<div styleName="error-message">
Since you joined Topcoder using your &lt;SSO Service&gt; account,
any email updates will need to be handled by logging in to
your &lt;SSO Service&gt; account.
</div>
)}
</div>

<div styleName="section-heading">
{!usingSsoService&& (
<div styleName="section-heading">
Retrieve or change your password
</div>
</div>
)}

<div className="form">
<ChangePasswordForm
onSubmit={(data) => changePassword(data)}
onReset={() => resetPassword()}
{...systemSettings}
/>
</div>
{!usingSsoService && (
<div className="form">
<ChangePasswordForm
onSubmit={(data) => changePassword(data)}
onReset={() => resetPassword()}
{...systemSettings}
/>
</div>
)}
</div>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@
display: flex;
flex-direction: column;
padding-bottom: 30px;

.error-message {
@include roboto-medium;

display: block;
border-radius: 5px;
background-color: $tc-red-10;
color: $tc-red-110;
font-size: 15px;
padding: 15px;
margin: 15px 40px;
line-height: 20px;
}
}

.username {
Expand Down Expand Up @@ -41,6 +54,7 @@
.input-container {
flex-grow: 1;


@media screen and (max-width: $screen-md - 1px) {
width: 100%;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,23 @@ import { connect } from 'react-redux'
import spinnerWhileLoading from '../../../../../components/LoadingSpinner'
import SettingsPanel from '../../../components/SettingsPanel'
import { checkEmailAvailability, changeEmail, changePassword, getSystemSettings, resetPassword } from '../../../actions'
import { getUserCredential } from '../../../../../actions/loadUser'
import { requiresAuthentication } from '../../../../../components/AuthenticatedComponent'
import SystemSettingsForm from '../components/SystemSettingsForm'
import './SystemSettingsContainer.scss'

const enhance = spinnerWhileLoading(props => !props.systemSettings.isLoading)
const enhance = spinnerWhileLoading(props => !props.systemSettings.isLoading && !props.isLoadingCredential)
const FormEnhanced = enhance(SystemSettingsForm)

class SystemSettingsContainer extends Component {
componentDidMount() {
this.props.getSystemSettings()
const {
getSystemSettings,
getUserCredential,
user
} = this.props
getSystemSettings()
getUserCredential(user.userId)
}

render() {
Expand All @@ -41,11 +48,14 @@ const SystemSettingsContainerWithAuth = requiresAuthentication(SystemSettingsCon

const mapStateToProps = ({ settings, loadUser }) => ({
systemSettings: settings.system,
user: loadUser.user
user: loadUser.user,
isLoadingCredential: loadUser.isLoadingCredential,
usingSsoService: _.get(loadUser, 'credential.hasPassword', false) === false,
})

const mapDispatchToProps = {
getSystemSettings,
getUserCredential,
checkEmailAvailability,
changeEmail,
changePassword,
Expand Down