Skip to content

Commit 3c5adbb

Browse files
authored
Merge pull request #4322 from yoution/issue-4249
fix: issue #4249
2 parents d75e512 + 94ab43c commit 3c5adbb

File tree

8 files changed

+111
-20
lines changed

8 files changed

+111
-20
lines changed

src/actions/loadUser.js

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import {
33
ACCOUNTS_APP_CONNECTOR_URL,
44
LOAD_USER_SUCCESS,
55
LOAD_USER_FAILURE,
6+
LOAD_USER_CREDENTIAL,
7+
LOAD_USER_CREDENTIAL_FAILURE,
68
LOAD_ORG_CONFIG_SUCCESS,
79
LOAD_ORG_CONFIG_FAILURE,
810
ROLE_ADMINISTRATOR,
@@ -16,7 +18,7 @@ import {
1618
ROLE_PRESALES, ROLE_PROJECT_MANAGER, ROLE_SOLUTION_ARCHITECT
1719
} from '../config/constants'
1820
import { getFreshToken, configureConnector, decodeToken } from 'tc-auth-lib'
19-
import { getUserProfile } from '../api/users'
21+
import { getUserProfile, getCredential } from '../api/users'
2022
import { fetchGroups } from '../api/groups'
2123
import { getOrgConfig } from '../api/orgConfig'
2224
import { EventTypes } from 'redux-segment'
@@ -26,6 +28,18 @@ configureConnector({
2628
frameId: 'tc-accounts-iframe'
2729
})
2830

31+
export function getUserCredential(userId) {
32+
return (dispatch) => {
33+
return dispatch({
34+
type: LOAD_USER_CREDENTIAL,
35+
payload: getCredential(userId)
36+
}).catch((err) => {
37+
console.log(err)
38+
dispatch({ type: LOAD_USER_CREDENTIAL_FAILURE })
39+
})
40+
}
41+
}
42+
2943
export function loadUser() {
3044
return ((dispatch, getState) => {
3145
const state = getState()
@@ -125,9 +139,9 @@ export function loadUserSuccess(dispatch, token) {
125139
loadGroups(dispatch, currentUser.userId)
126140
})
127141
.catch((err) => {
128-
// if we fail to load user's profile, still dispatch user load success
129-
// ideally it shouldn't happen, but if it is, we can render the page
130-
// without profile information
142+
// if we fail to load user's profile, still dispatch user load success
143+
// ideally it shouldn't happen, but if it is, we can render the page
144+
// without profile information
131145
console.log(err)
132146
dispatch({ type: LOAD_USER_SUCCESS, user : currentUser })
133147
})
@@ -161,7 +175,7 @@ function loadGroups(dispatch, userId) {
161175
}
162176
})
163177
.catch((err) => {
164-
// if we fail to load groups
178+
// if we fail to load groups
165179
console.log(err)
166180
})
167181
}

src/api/users.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,23 @@ export function getUserProfile(handle) {
1717
})
1818
}
1919

20+
21+
/**
22+
* Gets credential for the specified user id.
23+
*
24+
* NOTE: Only admins are authorized to use the underlying endpoint.
25+
*
26+
* @param {Number} userId The user id
27+
* @return {Promise} Resolves to the linked accounts array.
28+
*/
29+
export function getCredential(userId) {
30+
return axios.get(`${TC_API_URL}/v3/users/${userId}?fields=credential`)
31+
.then(resp => {
32+
return _.get(resp.data, 'result.content', {})
33+
})
34+
}
35+
36+
2037
/**
2138
* Update user profile
2239
*

src/config/constants.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ import { getCookie } from '../helpers/cookie'
77
export const LOAD_USER_SUCCESS = 'LOAD_USER_SUCCESS'
88
export const LOAD_USER_FAILURE = 'LOAD_USER_FAILURE'
99

10+
export const LOAD_USER_CREDENTIAL = 'LOAD_USER_CREDENTIAL'
11+
export const LOAD_USER_CREDENTIAL_PENDING = 'LOAD_USER_CREDENTIAL_PENDING'
12+
export const LOAD_USER_CREDENTIAL_SUCCESS = 'LOAD_USER_CREDENTIAL_SUCCESS'
13+
export const LOAD_USER_CREDENTIAL_FAILURE = 'LOAD_USER_CREDENTIAL_FAILURE'
14+
15+
1016
// Load organization configs
1117
export const LOAD_ORG_CONFIG_SUCCESS = 'LOAD_ORG_CONFIG_SUCCESS'
1218
export const LOAD_ORG_CONFIG_FAILURE = 'LOAD_ORG_CONFIG_FAILURE'

src/reducers/loadUser.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import _ from 'lodash'
22
import {
33
LOAD_USER_SUCCESS,
44
LOAD_USER_FAILURE,
5+
LOAD_USER_CREDENTIAL_PENDING,
6+
LOAD_USER_CREDENTIAL_SUCCESS,
7+
LOAD_USER_CREDENTIAL_FAILURE,
58
LOAD_ORG_CONFIG_SUCCESS,
69
LOAD_ORG_CONFIG_FAILURE,
710
SAVE_PROFILE_PHOTO_SUCCESS,
@@ -18,6 +21,19 @@ export const initialState = {
1821
export default function(state = initialState, action) {
1922
switch (action.type) {
2023

24+
case LOAD_USER_CREDENTIAL_PENDING:
25+
return Object.assign({}, state, {
26+
isLoadingCredential: true,
27+
})
28+
case LOAD_USER_CREDENTIAL_SUCCESS:
29+
return Object.assign({}, state, {
30+
isLoadingCredential: false,
31+
credential: action.payload.credential
32+
})
33+
case LOAD_USER_CREDENTIAL_FAILURE:
34+
return Object.assign({}, state, {
35+
isLoadingCredential: false,
36+
})
2137
case LOAD_USER_SUCCESS:
2238
return Object.assign({}, state, {
2339
isLoading : false,

src/routes/settings/routes/system/components/ChangeEmailForm.jsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ class ChangeEmailForm extends React.Component {
9898
}
9999

100100
render() {
101-
const { settings, checkingEmail, checkedEmail, isEmailAvailable, isEmailChanging, emailSubmitted} = this.props
101+
const {usingSsoService, settings, checkingEmail, checkedEmail, isEmailAvailable, isEmailChanging, emailSubmitted} = this.props
102102
const { currentEmail, isValid, isFocused } = this.state
103103
const currentEmailAvailable = checkedEmail === currentEmail && isEmailAvailable
104104
const isCheckingCurrentEmail = checkingEmail === currentEmail
@@ -140,7 +140,7 @@ class ChangeEmailForm extends React.Component {
140140
validationErrors={{
141141
isEmail: 'Provide a correct email'
142142
}}
143-
disabled={isEmailChanging || !hasPermission(PERMISSIONS.UPDATE_USER_EMAIL)}
143+
disabled={usingSsoService || isEmailChanging || !hasPermission(PERMISSIONS.UPDATE_USER_EMAIL)}
144144
ref={(ref) => this.emailRef = ref}
145145
/>
146146
{ isFocused && isCheckingCurrentEmail && (
@@ -174,6 +174,7 @@ class ChangeEmailForm extends React.Component {
174174

175175
ChangeEmailForm.propTypes = {
176176
email: PropTypes.string,
177+
usingSsoService: PropTypes.bool,
177178
onSubmit: PropTypes.func.isRequired,
178179
checkingEmail: PropTypes.string,
179180
checkedEmail: PropTypes.string,

src/routes/settings/routes/system/components/SystemSettingsForm.jsx

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const TCFormFields = FormsyForm.Fields
99

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

@@ -40,20 +40,33 @@ class SystemSettingsForm extends Component {
4040
checkEmailAvailability={checkEmailAvailability}
4141
onSubmit={(email) => changeEmail(email)}
4242
{...systemSettings}
43+
usingSsoService={usingSsoService}
4344
/>
45+
46+
{usingSsoService && (
47+
<div styleName="error-message">
48+
Since you joined Topcoder using your &lt;SSO Service&gt; account,
49+
any email updates will need to be handled by logging in to
50+
your &lt;SSO Service&gt; account.
51+
</div>
52+
)}
4453
</div>
4554

46-
<div styleName="section-heading">
55+
{!usingSsoService&& (
56+
<div styleName="section-heading">
4757
Retrieve or change your password
48-
</div>
58+
</div>
59+
)}
4960

50-
<div className="form">
51-
<ChangePasswordForm
52-
onSubmit={(data) => changePassword(data)}
53-
onReset={() => resetPassword()}
54-
{...systemSettings}
55-
/>
56-
</div>
61+
{!usingSsoService && (
62+
<div className="form">
63+
<ChangePasswordForm
64+
onSubmit={(data) => changePassword(data)}
65+
onReset={() => resetPassword()}
66+
{...systemSettings}
67+
/>
68+
</div>
69+
)}
5770
</div>
5871
)
5972
}

src/routes/settings/routes/system/components/SystemSettingsForm.scss

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,19 @@
44
display: flex;
55
flex-direction: column;
66
padding-bottom: 30px;
7+
8+
.error-message {
9+
@include roboto-medium;
10+
11+
display: block;
12+
border-radius: 5px;
13+
background-color: $tc-red-10;
14+
color: $tc-red-110;
15+
font-size: 15px;
16+
padding: 15px;
17+
margin: 15px 40px;
18+
line-height: 20px;
19+
}
720
}
821

922
.username {
@@ -41,6 +54,7 @@
4154
.input-container {
4255
flex-grow: 1;
4356

57+
4458
@media screen and (max-width: $screen-md - 1px) {
4559
width: 100%;
4660
}

src/routes/settings/routes/system/containers/SystemSettingsContainer.jsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,23 @@ import { connect } from 'react-redux'
77
import spinnerWhileLoading from '../../../../../components/LoadingSpinner'
88
import SettingsPanel from '../../../components/SettingsPanel'
99
import { checkEmailAvailability, changeEmail, changePassword, getSystemSettings, resetPassword } from '../../../actions'
10+
import { getUserCredential } from '../../../../../actions/loadUser'
1011
import { requiresAuthentication } from '../../../../../components/AuthenticatedComponent'
1112
import SystemSettingsForm from '../components/SystemSettingsForm'
1213
import './SystemSettingsContainer.scss'
1314

14-
const enhance = spinnerWhileLoading(props => !props.systemSettings.isLoading)
15+
const enhance = spinnerWhileLoading(props => !props.systemSettings.isLoading && !props.isLoadingCredential)
1516
const FormEnhanced = enhance(SystemSettingsForm)
1617

1718
class SystemSettingsContainer extends Component {
1819
componentDidMount() {
19-
this.props.getSystemSettings()
20+
const {
21+
getSystemSettings,
22+
getUserCredential,
23+
user
24+
} = this.props
25+
getSystemSettings()
26+
getUserCredential(user.userId)
2027
}
2128

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

4249
const mapStateToProps = ({ settings, loadUser }) => ({
4350
systemSettings: settings.system,
44-
user: loadUser.user
51+
user: loadUser.user,
52+
isLoadingCredential: loadUser.isLoadingCredential,
53+
usingSsoService: _.get(loadUser, 'credential.hasPassword', false) === false,
4554
})
4655

4756
const mapDispatchToProps = {
4857
getSystemSettings,
58+
getUserCredential,
4959
checkEmailAvailability,
5060
changeEmail,
5161
changePassword,

0 commit comments

Comments
 (0)