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
98 changes: 97 additions & 1 deletion docs/permissions.html
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ <h2>Project Members</h2>
<div class="text-black-50 small-text">Invite new members or delete them. There are some additional restrictions for some roles.</div>
</div>
<div class="col-9 py-2">
<span class="badge badge-primary" title="Allowed Project Role">copilot</span>
<span class="badge badge-primary" title="Allowed Project Role">manager</span>
<span class="badge badge-primary" title="Allowed Project Role">account_manager</span>
<span class="badge badge-primary" title="Allowed Project Role">account_executive</span>
Expand All @@ -93,6 +92,48 @@ <h2>Project Members</h2>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Admin</span>
</div>
</div>
<div class="row border-top">
<div class="col py-2">
Join topcoder team
<div><small><code>JOIN_TOPCODER_TEAM</code></small></div>
<div class="text-black-50 small-text">Join Topcoder Team without invitation</div>
</div>
<div class="col-9 py-2">
<span class="badge badge-success" title="Allowed Topcoder Role">administrator</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Admin</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Manager</span>
</div>
</div>
<div class="row border-top">
<div class="col py-2">
Manage copilots
<div><small><code>MANAGE_COPILOTS</code></small></div>
<div class="text-black-50 small-text">Directly invite copilots to the project.</div>
</div>
<div class="col-9 py-2">
<span class="badge badge-success" title="Allowed Topcoder Role">administrator</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Admin</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Copilot Manager</span>
</div>
</div>
<div class="row border-top">
<div class="col py-2">
Request copilots
<div><small><code>REQUEST_COPILOTS</code></small></div>
<div class="text-black-50 small-text">Request copilots to the project.</div>
</div>
<div class="col-9 py-2">
<span class="badge badge-primary" title="Allowed Project Role">manager</span>
<span class="badge badge-primary" title="Allowed Project Role">account_manager</span>
<span class="badge badge-primary" title="Allowed Project Role">account_executive</span>
<span class="badge badge-primary" title="Allowed Project Role">project_manager</span>
<span class="badge badge-primary" title="Allowed Project Role">program_manager</span>
<span class="badge badge-primary" title="Allowed Project Role">solution_architect</span>
<span class="badge badge-success" title="Allowed Topcoder Role">administrator</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Admin</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Copilot Manager</span>
</div>
</div>
<div class="row">
<div class="col pt-5 pb-2">
<h2>Topics &amp; Posts</h2>
Expand Down Expand Up @@ -188,6 +229,7 @@ <h2>User Profile</h2>
<span class="badge badge-success" title="Allowed Topcoder Role">administrator</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Admin</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Manager</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Copilot Manager</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Account Manager</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Business Development Representative</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Presales</span>
Expand All @@ -208,6 +250,7 @@ <h2>User Profile</h2>
<span class="badge badge-success" title="Allowed Topcoder Role">administrator</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Admin</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Manager</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Copilot Manager</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Account Manager</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Business Development Representative</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Presales</span>
Expand All @@ -217,6 +260,58 @@ <h2>User Profile</h2>
<span class="badge badge-success" title="Allowed Topcoder Role">Project Manager</span>
</div>
</div>
<div class="row border-top">
<div class="col py-2">
View User Profile as Copilot
<div><small><code>VIEW_USER_PROFILE_AS_COPILOT</code></small></div>
<div class="text-black-50 small-text"></div>
</div>
<div class="col-9 py-2">
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Copilot</span>
</div>
</div>
<div class="row border-top">
<div class="col py-2">
View User Profile as Topcoder Employee
<div><small><code>VIEW_USER_PROFILE_AS_TOPCODER_EMPLOYEE</code></small></div>
<div class="text-black-50 small-text"></div>
</div>
<div class="col-9 py-2">
<span class="badge badge-success" title="Allowed Topcoder Role">administrator</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Admin</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Manager</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Copilot Manager</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Account Manager</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Business Development Representative</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Presales</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Account Executive</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Program Manager</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Solution Architect</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Project Manager</span>
</div>
</div>
<div class="row border-top">
<div class="col py-2">
View User Profile as Customer
<div><small><code>VIEW_USER_PROFILE_AS_CUSTOMER</code></small></div>
<div class="text-black-50 small-text"></div>
</div>
<div class="col-9 py-2">
<span class="badge badge-success" title="Allowed Topcoder Role">Topcoder User</span>
<span class="badge badge-danger" title="Denied Topcoder Role">administrator</span>
<span class="badge badge-danger" title="Denied Topcoder Role">Connect Admin</span>
<span class="badge badge-danger" title="Denied Topcoder Role">Connect Manager</span>
<span class="badge badge-danger" title="Denied Topcoder Role">Connect Copilot Manager</span>
<span class="badge badge-danger" title="Denied Topcoder Role">Connect Account Manager</span>
<span class="badge badge-danger" title="Denied Topcoder Role">Business Development Representative</span>
<span class="badge badge-danger" title="Denied Topcoder Role">Presales</span>
<span class="badge badge-danger" title="Denied Topcoder Role">Account Executive</span>
<span class="badge badge-danger" title="Denied Topcoder Role">Program Manager</span>
<span class="badge badge-danger" title="Denied Topcoder Role">Solution Architect</span>
<span class="badge badge-danger" title="Denied Topcoder Role">Project Manager</span>
<span class="badge badge-danger" title="Denied Topcoder Role">Connect Copilot</span>
</div>
</div>
<div class="row">
<div class="col pt-5 pb-2">
<h2>View Member Suggestions</h2>
Expand Down Expand Up @@ -251,6 +346,7 @@ <h2>My Projects Filter</h2>
<span class="badge badge-success" title="Allowed Topcoder Role">administrator</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Admin</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Manager</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Copilot Manager</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Connect Account Manager</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Business Development Representative</span>
<span class="badge badge-success" title="Allowed Topcoder Role">Presales</span>
Expand Down
44 changes: 22 additions & 22 deletions src/config/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -1039,38 +1039,21 @@ export const PROJECT_CATEGORY_TAAS = 'talent-as-a-service'
* - if field is not on the list means it should not be shown
*/
export const PROFILE_FIELDS_CONFIG = {
// this config is used to show any user profile
DEFAULT: {
// required fields
firstName: true,
lastName: true,
country: true,
title: true,
timeZone: true,
businessPhone: true,
companyName: true,

// optional fields
avatar: false,
workingHourStart: false,
workingHourEnd: false,
},

// configs below are used when we ask users to fill missing fields (progressive registration)
TOPCODER: {
// required fields
firstName: true,
lastName: true,
title: true,
country: true,
timeZone: true,
workingHourStart: true,
workingHourEnd: true,

// optional fields
avatar: false,
title: false,
companyName: false,
businessPhone: false,
// companyName: false,
// companyURL: false,
// businessPhone: false,
},
CUSTOMER: {
// required fields
Expand All @@ -1079,13 +1062,30 @@ export const PROFILE_FIELDS_CONFIG = {
country: true,
title: true,
companyName: true,
companyURL: true,
businessPhone: true,
businessEmail: true,

// optional fields
businessEmail: false,
avatar: false,
timeZone: false,
workingHourStart: false,
workingHourEnd: false,
},
COPILOT: {
// required fields
firstName: true,
lastName: true,
country: true,
timeZone: true,
workingHourStart: true,
workingHourEnd: true,

// optional fields
avatar: false,
// title: false,
// companyName: false,
// companyURL: true,
// businessPhone: false,
}
}
37 changes: 37 additions & 0 deletions src/config/permissions.js
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,43 @@ export default {
],
},

VIEW_USER_PROFILE_AS_COPILOT: {
_meta: {
group: 'User Profile',
title: 'View User Profile as Copilot',
},
topcoderRoles: [
ROLE_CONNECT_COPILOT
],
},

VIEW_USER_PROFILE_AS_TOPCODER_EMPLOYEE: {
_meta: {
group: 'User Profile',
title: 'View User Profile as Topcoder Employee',
},
topcoderRoles: [
..._.difference(TOPCODER_ALL, [ROLE_TOPCODER_USER, ROLE_CONNECT_COPILOT])
],
},

VIEW_USER_PROFILE_AS_CUSTOMER: {
_meta: {
group: 'User Profile',
title: 'View User Profile as Customer',
},
allowRule: {
topcoderRoles: [
ROLE_TOPCODER_USER
]
},
denyRule: {
topcoderRoles: [
..._.difference(TOPCODER_ALL, [ROLE_TOPCODER_USER])
],
}
},

SEE_MEMBER_SUGGESTIONS: {
_meta: {
group: 'View Member Suggestions',
Expand Down
21 changes: 21 additions & 0 deletions src/helpers/tcHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
NON_CUSTOMER_ROLES,
PROFILE_FIELDS_CONFIG,
} from '../config/constants'
import { hasPermission } from './permissions'
import PERMISSIONS from '../config/permissions'

/**
* Check if a user is a special system user
Expand Down Expand Up @@ -73,3 +75,22 @@ export const isUserProfileComplete = (user, profileSettings) => {

return !isMissingUserInfo
}

/**
* Get User Profile fields config based on the current user roles.
*
* @returns {Object} fields config
*/
export const getUserProfileFieldsConfig = () => {
if (hasPermission(PERMISSIONS.VIEW_USER_PROFILE_AS_TOPCODER_EMPLOYEE)) {
return PROFILE_FIELDS_CONFIG.TOPCODER
}

if (hasPermission(PERMISSIONS.VIEW_USER_PROFILE_AS_COPILOT)) {
return PROFILE_FIELDS_CONFIG.COPILOT
}

if (hasPermission(PERMISSIONS.VIEW_USER_PROFILE_AS_CUSTOMER)) {
return PROFILE_FIELDS_CONFIG.CUSTOMER
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import ISOCountries from '../../../../../helpers/ISOCountries'
import { formatPhone } from '../../../../../helpers/utils'
import { hasPermission } from '../../../../../helpers/permissions'
import PERMISSIONS from '../../../../../config/permissions'
import { PROFILE_FIELDS_CONFIG } from '../../../../../config/constants'
import './ProfileSettingsForm.scss'

const countries = _.orderBy(ISOCountries, ['name'], ['asc']).map((country) => ({
Expand Down Expand Up @@ -137,6 +136,11 @@ class ProfileSettingsForm extends Component {
validationErrors.isEmail = 'Please, enter correct email'
}

if (name === 'companyURL') {
validations.isRelaxedUrl = true
validationErrors.isRelaxedUrl = 'Please, enter correct URL'
}

return (
<div className="field">
<div className="label">
Expand Down Expand Up @@ -235,13 +239,11 @@ class ProfileSettingsForm extends Component {
{!_.isUndefined(fieldsConfig.firstName) && this.getField('First Name', 'firstName', fieldsConfig.firstName)}
{!_.isUndefined(fieldsConfig.lastName) && this.getField('Last Name', 'lastName', fieldsConfig.lastName)}
{!_.isUndefined(fieldsConfig.title) && this.getField('Title', 'title', fieldsConfig.title)}
{!_.isUndefined(fieldsConfig.businessEmail) &&
this.getField('Business Email', 'businessEmail', fieldsConfig.businessEmail, true)}
{!_.isUndefined(fieldsConfig.businessPhone) && (
<div className="field">
<div className="label">
<span styleName="fieldLabelText">Business Phone</span>&nbsp;
<sup styleName="requiredMarker">*</sup>
{fieldsConfig.businessPhone && <sup styleName="requiredMarker">*</sup>}
</div>
<div className="input-field">
<PhoneInput
Expand Down Expand Up @@ -275,13 +277,9 @@ class ProfileSettingsForm extends Component {
</div>
</div>
)}
{!_.isUndefined(fieldsConfig.companyName) &&
this.getField(
'Company Name',
'companyName',
fieldsConfig.companyName,
disableCompanyInput
)}
{!_.isUndefined(fieldsConfig.businessEmail) && this.getField('Business Email', 'businessEmail', fieldsConfig.businessEmail, true)}
{!_.isUndefined(fieldsConfig.companyName) && this.getField('Company Name', 'companyName', fieldsConfig.companyName, disableCompanyInput)}
{!_.isUndefined(fieldsConfig.companyURL) && this.getField('Company URL', 'companyURL', fieldsConfig.companyURL)}
{!_.isUndefined(fieldsConfig.country) && (
<div className="field">
{fieldsConfig.country ? (
Expand Down Expand Up @@ -414,8 +412,6 @@ class ProfileSettingsForm extends Component {
}

ProfileSettingsForm.defaultProps = {
// default config is same for user profile for any kind of users
fieldsConfig: PROFILE_FIELDS_CONFIG.DEFAULT,
showBackButton: false,
submitButton: 'Save settings',
onBack: () => {},
Expand All @@ -434,6 +430,7 @@ ProfileSettingsForm.propTypes = {
lastName: PropTypes.bool,
title: PropTypes.bool,
companyName: PropTypes.bool,
companyURL: PropTypes.bool,
businessPhone: PropTypes.bool,
businessEmail: PropTypes.bool,
country: PropTypes.bool,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import spinnerWhileLoading from '../../../../../components/LoadingSpinner'
import { requiresAuthentication } from '../../../../../components/AuthenticatedComponent'
import { getProfileSettings, saveProfileSettings, uploadProfilePhoto } from '../../../actions/index'
import { formatProfileSettings } from '../../../helpers/settings'
import { getUserProfileFieldsConfig } from '../../../../../helpers/tcHelpers'

const enhance = spinnerWhileLoading(props => !props.values.isLoading)
const ProfileSettingsFormEnhanced = enhance(ProfileSettingsForm)
Expand All @@ -20,6 +21,7 @@ class ProfileSettingsContainer extends Component {

render() {
const { profileSettings, saveProfileSettings, uploadProfilePhoto, user } = this.props
const fieldsConfig = getUserProfileFieldsConfig()

return (
<SettingsPanel
Expand All @@ -31,6 +33,7 @@ class ProfileSettingsContainer extends Component {
values={profileSettings}
saveSettings={saveProfileSettings}
uploadPhoto={uploadProfilePhoto}
fieldsConfig={fieldsConfig}
/>
</SettingsPanel>
)
Expand Down