Skip to content

Commit 264d7c9

Browse files
committed
[challenge] Add BA management functionality - veshu submission
1 parent a9b1b17 commit 264d7c9

File tree

13 files changed

+526
-76
lines changed

13 files changed

+526
-76
lines changed

config/constants/development.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,7 @@ module.exports = {
5555
HEADER_AUTH_URLS_HREF: `https://accounts-auth0.${DOMAIN}?utm_source=community-app-main`,
5656
HEADER_AUTH_URLS_LOCATION: `https://accounts-auth0.${DOMAIN}?retUrl=%S&utm_source=community-app-main`,
5757
SKILLS_V5_API_URL: `${API_V5}/standardized-skills/skills/autocomplete`,
58-
UPDATE_SKILLS_V5_API_URL: `${API_V5}/standardized-skills/challenge-skills`
58+
UPDATE_SKILLS_V5_API_URL: `${API_V5}/standardized-skills/challenge-skills`,
59+
SALESFORCE_BILLING_ACCOUNT_LINK: 'https://c.cs18.visual.force.com/apex/baredirect?id=',
60+
TYPEFORM_URL: 'https://topcoder.typeform.com/to/YJ7AL4p8'
5961
}

config/constants/production.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,7 @@ module.exports = {
5252
HEADER_AUTH_URLS_HREF: `https://accounts-auth0.${DOMAIN}?utm_source=community-app-main`,
5353
HEADER_AUTH_URLS_LOCATION: `https://accounts-auth0.${DOMAIN}?retUrl=%S&utm_source=community-app-main`,
5454
SKILLS_V5_API_URL: `${API_V5}/standardized-skills/skills/autocomplete`,
55-
UPDATE_SKILLS_V5_API_URL: `${API_V5}/standardized-skills/challenge-skills`
55+
UPDATE_SKILLS_V5_API_URL: `${API_V5}/standardized-skills/challenge-skills`,
56+
SALESFORCE_BILLING_ACCOUNT_LINK: 'https://topcoder.my.salesforce.com/apex/baredirect?id=',
57+
TYPEFORM_URL: 'https://topcoder.typeform.com/to/YJ7AL4p8'
5658
}

src/actions/projects.js

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,18 @@ import {
66
LOAD_CHALLENGE_MEMBERS,
77
LOAD_PROJECT_TYPES,
88
CREATE_PROJECT,
9-
UPDATE_PROJECT
9+
LOAD_PROJECT_BILLING_ACCOUNTS,
10+
UPDATE_PROJECT_PENDING,
11+
UPDATE_PROJECT_SUCCESS,
12+
UPDATE_PROJECT_FAILURE
1013
} from '../config/constants'
1114
import {
1215
fetchProjectById,
1316
fetchBillingAccount,
1417
fetchProjectPhases,
1518
getProjectTypes,
1619
createProjectApi,
20+
fetchBillingAccounts,
1721
updateProjectApi
1822
} from '../services/projects'
1923

@@ -32,6 +36,11 @@ export function loadProject (projectId, filterMembers = true) {
3236
payload: members
3337
})
3438
}
39+
// Loads billing account
40+
dispatch({
41+
type: LOAD_PROJECT_BILLING_ACCOUNTS,
42+
payload: fetchBillingAccounts(projectId)
43+
})
3544

3645
// Loads billing account
3746
dispatch({
@@ -75,18 +84,6 @@ export function createProject (project) {
7584
}
7685
}
7786

78-
/**
79-
* Updates a project
80-
*/
81-
export function updateProject (projectId, project) {
82-
return (dispatch) => {
83-
return dispatch({
84-
type: UPDATE_PROJECT,
85-
payload: updateProjectApi(projectId, project)
86-
})
87-
}
88-
}
89-
9087
export function reloadProjectMembers (projectId) {
9188
return (dispatch) => {
9289
return dispatch({
@@ -101,3 +98,38 @@ export function reloadProjectMembers (projectId) {
10198
})
10299
}
103100
}
101+
102+
/**
103+
* Updates project details
104+
* @param {string} projectId - The project ID
105+
* @param {object} updatedProps - The updated project details
106+
* @returns {Promise<object>} The updated project
107+
*/
108+
export function updateProject (projectId, updatedProps) {
109+
return async (dispatch) => {
110+
dispatch({
111+
type: UPDATE_PROJECT_PENDING
112+
})
113+
return updateProjectApi(projectId, updatedProps).then((project) => {
114+
// refresh billing account
115+
dispatch({
116+
type: LOAD_PROJECT_BILLING_ACCOUNT,
117+
payload: fetchBillingAccount(projectId)
118+
})
119+
dispatch({
120+
type: LOAD_PROJECT_BILLING_ACCOUNTS,
121+
payload: fetchBillingAccounts(projectId)
122+
})
123+
return dispatch({
124+
type: UPDATE_PROJECT_SUCCESS,
125+
payload: project
126+
})
127+
}).catch((e) => {
128+
dispatch({
129+
type: UPDATE_PROJECT_FAILURE,
130+
error: e
131+
})
132+
return Promise.reject(e)
133+
})
134+
}
135+
}

src/components/Buttons/OutlineButton/index.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import cn from 'classnames'
66
import styles from './Outline.module.scss'
77
import _ from 'lodash'
88

9-
const OutlineButton = ({ type, text, link, onClick, url, className, submit, disabled }) => {
9+
const OutlineButton = ({ type, text, link, onClick, url, className, submit, disabled, target = 'self' }) => {
1010
if (_.isEmpty(link) && _.isEmpty(url)) {
1111
return (
1212
<button
@@ -29,7 +29,7 @@ const OutlineButton = ({ type, text, link, onClick, url, className, submit, disa
2929
}
3030

3131
return (
32-
<a className={cn(styles.container, styles[type], className)} href={`${url}`}>
32+
<a className={cn(styles.container, styles[type], className)} href={`${url}`} target={target}>
3333
<span>{text}</span>
3434
</a>
3535
)
@@ -43,7 +43,8 @@ OutlineButton.propTypes = {
4343
className: PropTypes.string,
4444
onClick: PropTypes.func,
4545
submit: PropTypes.bool,
46-
disabled: PropTypes.bool
46+
disabled: PropTypes.bool,
47+
target: PropTypes.oneOf(['_blank', 'self'])
4748
}
4849

4950
export default OutlineButton

src/components/ChallengesComponent/ChallengeList/index.js

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import Message from '../Message'
2222
import SortIcon from '../../../assets/images/sort-icon.svg'
2323
import Select from '../../Select'
2424
import Loader from '../../Loader'
25+
import UpdateBillingAccount from '../../UpdateBillingAccount'
2526

2627
import { CHALLENGE_STATUS, PAGE_SIZE, PAGINATION_PER_PAGE_OPTIONS, PROJECT_ROLES } from '../../../config/constants'
2728
import { checkAdmin, checkReadOnlyRoles } from '../../../util/tc'
@@ -393,13 +394,18 @@ class ChallengeList extends Component {
393394
setActiveProject,
394395
billingStartDate,
395396
billingEndDate,
397+
currentBillingAccount,
398+
billingAccounts,
399+
isBillingAccountsLoading,
400+
updateProject,
396401
isBillingAccountLoadingFailed,
397402
isBillingAccountLoading,
398403
selfService,
399404
challengeTypes,
400405
loginUserRoleInProject
401406
} = this.props
402407
const isReadOnly = checkReadOnlyRoles(this.props.auth.token) || loginUserRoleInProject === PROJECT_ROLES.READ
408+
const isAdmin = checkAdmin(this.props.auth.token)
403409

404410
if (warnMessage) {
405411
return <Message warnMessage={warnMessage} />
@@ -476,40 +482,23 @@ class ChallengeList extends Component {
476482
<div className={styles.list}>
477483
{dashboard && <h2>My Challenges</h2>}
478484
<div className={cn(styles.row, { [styles.dashboardRow]: dashboard })}>
479-
{!dashboard &&
480-
!isBillingAccountLoading &&
481-
!isBillingAccountLoadingFailed &&
482-
!isBillingAccountExpired && (
485+
{!dashboard ? (
483486
<div className={styles['col-6']}>
484-
<span className={styles.title}>Billing Account: </span>
485-
<span className={styles.active}>ACTIVE</span> &nbsp;{' '}
486-
<span className={styles.title}>Start Date:</span>{' '}
487-
{billingStartDate} &nbsp;{' '}
488-
<span className={styles.title}>End Date:</span> {billingEndDate}
489-
</div>
490-
)}
491-
{!dashboard &&
492-
!isBillingAccountLoading &&
493-
!isBillingAccountLoadingFailed &&
494-
isBillingAccountExpired && (
495-
<div className={styles['col-6']}>
496-
<span className={styles.title}>Billing Account: </span>
497-
<span className={styles.inactive}>INACTIVE</span> &nbsp;{' '}
498-
<span className={styles.title}>Start Date:</span>{' '}
499-
{billingStartDate} &nbsp;{' '}
500-
<span className={styles.title}>End Date:</span> {billingEndDate}
501-
</div>
502-
)}
503-
{!dashboard &&
504-
!isBillingAccountLoading &&
505-
isBillingAccountLoadingFailed && (
506-
<div className={styles['col-6']}>
507-
<span className={styles.error}>
508-
Billing Account failed to load
509-
</span>
487+
<UpdateBillingAccount
488+
billingAccounts={billingAccounts}
489+
isBillingAccountsLoading={isBillingAccountsLoading}
490+
isBillingAccountLoading={isBillingAccountLoading}
491+
isBillingAccountLoadingFailed={isBillingAccountLoadingFailed}
492+
billingStartDate={billingStartDate}
493+
billingEndDate={billingEndDate}
494+
isBillingAccountExpired={isBillingAccountExpired}
495+
isAdmin={isAdmin}
496+
currentBillingAccount={currentBillingAccount}
497+
updateProject={updateProject}
498+
projectId={activeProject.id}
499+
/>
510500
</div>
511-
)}
512-
{dashboard && (
501+
) : (
513502
<div className={styles['col-6']}>
514503
<div className={cn(styles.field, styles.input1)}>
515504
<label htmlFor='project'>Project :</label>
@@ -888,6 +877,10 @@ ChallengeList.propTypes = {
888877
deleteChallenge: PropTypes.func.isRequired,
889878
isBillingAccountExpired: PropTypes.bool,
890879
billingStartDate: PropTypes.string,
880+
currentBillingAccount: PropTypes.number,
881+
updateProject: PropTypes.func.isRequired,
882+
isBillingAccountsLoading: PropTypes.bool,
883+
billingAccounts: PropTypes.arrayOf(PropTypes.shape()).isRequired,
891884
isLoading: PropTypes.bool,
892885
billingEndDate: PropTypes.string,
893886
isBillingAccountLoadingFailed: PropTypes.bool,

src/components/ChallengesComponent/ChallengesComponent.module.scss

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@import '../../styles/includes';
1+
@import "../../styles/includes";
22

33
.challenges {
44
width: 100%;
@@ -35,7 +35,11 @@
3535
display: flex;
3636
justify-content: space-between;
3737
padding: 0 30px;
38+
}
3839

40+
.col-6 {
41+
flex: 0 0 50%;
42+
max-width: 50%;
3943
}
4044

4145
.titleLinks {
@@ -56,15 +60,19 @@
5660
margin-left: 20px;
5761
}
5862
}
63+
.projectActionButtonWrapper {
64+
display: flex;
65+
gap: 5px;
5966

60-
.buttonLaunchNew {
61-
min-width: 169px;
62-
height: 40px;
63-
text-decoration: none;
67+
a {
68+
min-width: 169px;
69+
height: 40px;
70+
text-decoration: none;
6471

65-
:global {
66-
span {
67-
margin: 0 20px;
72+
:global {
73+
span {
74+
margin: 0 20px;
75+
}
6876
}
6977
}
7078
}

src/components/ChallengesComponent/index.js

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ import _ from 'lodash'
66
import PropTypes from 'prop-types'
77
import { Helmet } from 'react-helmet'
88
import { Link } from 'react-router-dom'
9-
import { PROJECT_ROLES } from '../../config/constants'
10-
import { PrimaryButton } from '../Buttons'
9+
import ProjectStatus from './ProjectStatus'
10+
import { PROJECT_ROLES, TYPEFORM_URL } from '../../config/constants'
11+
import { PrimaryButton, OutlineButton } from '../Buttons'
1112
import ChallengeList from './ChallengeList'
1213
import styles from './ChallengesComponent.module.scss'
13-
import { checkReadOnlyRoles, checkAdminOrCopilot } from '../../util/tc'
14-
import ProjectStatus from './ProjectStatus'
14+
import { checkAdmin, checkReadOnlyRoles, checkAdminOrCopilot } from '../../util/tc'
15+
1516
const ChallengesComponent = ({
1617
challenges,
1718
projects,
@@ -37,6 +38,10 @@ const ChallengesComponent = ({
3738
isBillingAccountExpired,
3839
billingStartDate,
3940
billingEndDate,
41+
billingAccounts,
42+
currentBillingAccount,
43+
updateProject,
44+
isBillingAccountsLoading,
4045
isBillingAccountLoadingFailed,
4146
isBillingAccountLoading,
4247
selfService,
@@ -77,12 +82,21 @@ const ChallengesComponent = ({
7782
)}
7883
</div>
7984
{activeProject && activeProject.id && !isReadOnly ? (
80-
<Link
81-
className={styles.buttonLaunchNew}
82-
to={`/projects/${activeProject.id}/challenges/new`}
83-
>
84-
<PrimaryButton text={'Launch New'} type={'info'} />
85-
</Link>
85+
<div className={styles.projectActionButtonWrapper}>
86+
{checkAdmin(auth.token) && (
87+
<OutlineButton
88+
text='Request Copilot'
89+
type={'info'}
90+
url={`${TYPEFORM_URL}#handle=${auth.user.handle}&projectid=${activeProjectId}`}
91+
target={'_blank'}
92+
/>
93+
)}
94+
<Link
95+
to={`/projects/${activeProject.id}/challenges/new`}
96+
>
97+
<PrimaryButton text={'Launch New'} type={'info'} />
98+
</Link>
99+
</div>
86100
) : (
87101
<span />
88102
)}
@@ -113,6 +127,10 @@ const ChallengesComponent = ({
113127
isBillingAccountExpired={isBillingAccountExpired}
114128
billingStartDate={billingStartDate}
115129
billingEndDate={billingEndDate}
130+
billingAccounts={billingAccounts}
131+
currentBillingAccount={currentBillingAccount}
132+
updateProject={updateProject}
133+
isBillingAccountsLoading={isBillingAccountsLoading}
116134
isBillingAccountLoadingFailed={isBillingAccountLoadingFailed}
117135
isBillingAccountLoading={isBillingAccountLoading}
118136
selfService={selfService}
@@ -153,6 +171,10 @@ ChallengesComponent.propTypes = {
153171
dashboard: PropTypes.bool,
154172
billingStartDate: PropTypes.string,
155173
billingEndDate: PropTypes.string,
174+
billingAccounts: PropTypes.arrayOf(PropTypes.shape()),
175+
updateProject: PropTypes.func.isRequired,
176+
isBillingAccountsLoading: PropTypes.bool,
177+
currentBillingAccount: PropTypes.number,
156178
isBillingAccountLoadingFailed: PropTypes.bool,
157179
isBillingAccountLoading: PropTypes.bool,
158180
selfService: PropTypes.bool,

0 commit comments

Comments
 (0)