Skip to content

Commit 0dac1df

Browse files
author
vikasrohit
authored
Merge pull request #4390 from yoution/feature/shapeup_billing_account_protection
TC Billing Account Enhancement
2 parents 1ae63f7 + 7f6984f commit 0dac1df

File tree

13 files changed

+92
-13
lines changed

13 files changed

+92
-13
lines changed

src/api/billingAccounts.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,14 @@ export function fetchBillingAccounts(projectId) {
1212
return axios.get(`${TC_API_URL}/v5/projects/${projectId}/billingAccounts`)
1313
}
1414

15+
16+
/**
17+
* Get billing account based on project id
18+
*
19+
* @param {String} projectId Id of the project
20+
*
21+
* @returns {Promise<Object>} Billing account data
22+
*/
23+
export function fetchBillingAccount(projectId) {
24+
return axios.get(`${TC_API_URL}/v5/projects/${projectId}/billingAccount`)
25+
}
Lines changed: 13 additions & 0 deletions
Loading

src/config/constants.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,13 @@ export const CLEAR_PROJECT_SUGGESTIONS_SEARCH = 'CLEAR_PROJECT_SUGGESTIONS_SEA
120120
export const PROJECT_SUGGESTIONS_SEARCH_FAILURE = 'PROJECT_SUGGESTIONS_SEARCH_FAILURE'
121121
export const PROJECT_SUGGESTIONS_SEARCH_SUCCESS = 'PROJECT_SUGGESTIONS_SEARCH_SUCCESS'
122122

123+
124+
// project billingAccount
125+
export const LOAD_PROJECT_BILLING_ACCOUNT = 'LOAD_PROJECT_BILLING_ACCOUNT'
126+
export const LOAD_PROJECT_BILLING_ACCOUNT_PENDING = 'LOAD_PROJECT_BILLING_ACCOUNT_PENDING'
127+
export const LOAD_PROJECT_BILLING_ACCOUNT_FAILURE = 'LOAD_PROJECT_BILLING_ACCOUNT_FAILURE'
128+
export const LOAD_PROJECT_BILLING_ACCOUNT_SUCCESS = 'LOAD_PROJECT_BILLING_ACCOUNT_SUCCESS'
129+
123130
// Project Dashboard
124131
export const LOAD_PROJECT_DASHBOARD = 'LOAD_PROJECT_DASHBOARD'
125132
export const LOAD_PROJECT_DASHBOARD_PENDING = 'LOAD_PROJECT_DASHBOARD_PENDING'

src/helpers/projectHelper.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import ReportsIcon from '../assets/icons/v.2.5/icon-reports.svg'
2020
import AssetsLibraryIcon from '../assets/icons/v.2.5/icon-assets-library.svg'
2121
import FAQIcon from '../assets/icons/faq.svg'
2222
import AccountSecurityIcon from 'assets/icons/v.2.5/icon-account-security.svg'
23+
import WarningIcon from '../assets/icons/v.2.5/icon-warning.svg'
2324
import InvisibleIcon from '../assets/icons/invisible.svg'
2425

2526
import { formatNumberWithCommas } from './format'
@@ -259,8 +260,9 @@ export function getNewProjectLink(orgConfigs) {
259260
* Get the list of navigation links for project details view
260261
* @param {Object} project - The project object
261262
* @param {string} projectId - The project id
263+
* @param {boolean} isBillingAccountExpired - is billingAccount expired
262264
*/
263-
export function getProjectNavLinks(project, projectId, renderFAQs) {
265+
export function getProjectNavLinks(project, projectId, renderFAQs, isBillingAccountExpired) {
264266
let messagesTab = null
265267
// `Discussions` items can be added as soon as project is loaded
266268
// if discussions are not hidden for it
@@ -289,7 +291,11 @@ export function getProjectNavLinks(project, projectId, renderFAQs) {
289291
}
290292

291293
if (hasPermission(PERMISSIONS.VIEW_PROJECT_SETTINGS)) {
292-
navLinks.push({ label: 'Project Settings', to: `/projects/${projectId}/settings`, Icon: AccountSecurityIcon, iconClassName: 'stroke' })
294+
if (!isBillingAccountExpired) {
295+
navLinks.push({ label: 'Project Settings', to: `/projects/${projectId}/settings`, Icon: AccountSecurityIcon, iconClassName: 'stroke' })
296+
}else {
297+
navLinks.push({ label: <span>Project Settings <WarningIcon style={{position: 'absolute', marginLeft: '5px'}}/></span>, to: `/projects/${projectId}/settings`, Icon: AccountSecurityIcon, iconClassName: 'stroke' })
298+
}
293299
}
294300

295301
return navLinks

src/projects/actions/project.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { getProjectById,
1313
createScopeChangeRequest as createScopeChangeRequestAPI,
1414
updateScopeChangeRequest as updateScopeChangeRequestAPI,
1515
} from '../../api/projects'
16+
import {fetchBillingAccount} from '../../api/billingAccounts'
1617
import {
1718
getProjectInviteById,
1819
getProjectMemberInvites,
@@ -26,6 +27,7 @@ import {
2627
} from '../../api/projectMembers'
2728
// import { loadProductTimelineWithMilestones } from './productsTimelines'
2829
import {
30+
LOAD_PROJECT_BILLING_ACCOUNT,
2931
LOAD_PROJECT,
3032
LOAD_PROJECT_MEMBER_INVITE,
3133
CREATE_PROJECT,
@@ -661,6 +663,15 @@ export function loadProjectMembers(projectId) {
661663
}
662664
}
663665

666+
export function loadProjectBillingAccount(projectId) {
667+
return (dispatch) => {
668+
return dispatch({
669+
type: LOAD_PROJECT_BILLING_ACCOUNT,
670+
payload: fetchBillingAccount(projectId)
671+
})
672+
}
673+
}
674+
664675
export function loadProjectMemberInvites(projectId) {
665676
return (dispatch) => {
666677
return dispatch({

src/projects/actions/projectDashboard.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import _ from 'lodash'
2-
import { loadProject, loadProjectInvite, loadProjectMembers, loadProjectMemberInvites } from './project'
2+
import { loadProject, loadProjectBillingAccount, loadProjectInvite, loadProjectMembers, loadProjectMemberInvites } from './project'
33
import { loadProjectPlan } from './projectPlan'
44
import { loadProjectsMetadata } from '../../actions/templates'
55
import { LOAD_PROJECT_DASHBOARD, LOAD_ADDITIONAL_PROJECT_DATA } from '../../config/constants'
@@ -27,10 +27,13 @@ const getDashboardData = (dispatch, getState, projectId, isOnlyLoadProjectInfo)
2727
//dispatch(loadMembers(userIds)),
2828
dispatch(loadProjectMembers(projectId)),
2929
dispatch(loadProjectMemberInvites(projectId))
30+
3031
]
3132
if (isOnlyLoadProjectInfo) {
3233
promises = []
3334
}
35+
// load project billingAccounts
36+
promises.push(dispatch(loadProjectBillingAccount(projectId)))
3437

3538
// for new projects load phases, products, project template and product templates
3639
if (['v3', 'v4'].indexOf(project.version) !== -1) {

src/projects/detail/components/BillingAccountField/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ class BillingAccountField extends React.Component {
7777
}
7878

7979
render() {
80+
81+
const {isExpired} = this.props
8082
const placeholder = this.state.billingAccounts.length > 0
8183
? 'Select billing account'
8284
: 'No Billing Account Available'
@@ -92,6 +94,7 @@ class BillingAccountField extends React.Component {
9294
isDisabled={this.state.billingAccounts.length === 0}
9395
showDropdownIndicator
9496
/>
97+
{isExpired && <span className="error-message">Expired</span>}
9598
{this.state.selectedBillingAccount && (
9699
<div className={styles.manageBillingAccountLinkWrapper}>
97100
<a

src/projects/detail/components/EditProjectDefaultsForm/EditProjectDefaultsForm.jsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {connect} from 'react-redux'
33
import _ from 'lodash'
44
import FormsyForm from 'appirio-tech-react-components/components/Formsy'
55
const Formsy = FormsyForm.Formsy
6-
import { updateProject } from '../../../actions/project'
6+
import { updateProject, loadProjectBillingAccount } from '../../../actions/project'
77
import NDAField from '../NDAField'
88
import GroupsField from '../GroupsField'
99
import BillingAccountField from '../BillingAccountField'
@@ -52,7 +52,7 @@ class EditProjectDefaultsForm extends React.Component {
5252
}
5353

5454
handleSubmit() {
55-
const {updateProject} = this.props
55+
const {updateProject, loadProjectBillingAccount} = this.props
5656
const {id} = this.props.project
5757
const updateProjectObj = Object.keys(this.state.project)
5858
.filter(key => !_.isEqual(this.props.project[key], this.state.project[key]))
@@ -61,7 +61,7 @@ class EditProjectDefaultsForm extends React.Component {
6161
return acc
6262
}, {})
6363
updateProject(id, updateProjectObj)
64-
.then(() => this.setState({enableButton: false}))
64+
.then(() => this.setState({enableButton: false})).then(() => loadProjectBillingAccount(id))
6565
.catch(console.error)
6666
}
6767

@@ -86,6 +86,7 @@ class EditProjectDefaultsForm extends React.Component {
8686
<BillingAccountField
8787
name="billingAccountId"
8888
projectId={this.state.project.id}
89+
isExpired={this.props.isBillingAccountExpired}
8990
value={this.state.project.billingAccountId}
9091
/>
9192
</div>
@@ -105,7 +106,8 @@ class EditProjectDefaultsForm extends React.Component {
105106
}
106107

107108
const mapDispatchToProps = {
108-
updateProject
109+
updateProject,
110+
loadProjectBillingAccount
109111
}
110112

111113
export default protectComponent(

src/projects/detail/components/timeline/CreateMilestoneForm/CreateMilestoneForm.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ class CreateMilestoneForm extends React.Component {
3434
cancelEdit() {
3535
const { previousMilestone } = this.props
3636
const startDate = previousMilestone ? moment.utc(previousMilestone.completionDate || previousMilestone.endDate) : moment.utc()
37-
this.setState({
37+
this.state = {
3838
isEditing: false,
3939
type: '',
4040
name: '',
4141
startDate: startDate.format('YYYY-MM-DD'),
4242
endDate: startDate.add(3, 'days').format('YYYY-MM-DD')
43-
})
43+
}
4444
}
4545

4646
onAddClick() {

src/projects/detail/containers/ProjectDefaultsContainer.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class ProjectDefaultsContainer extends Component {
1818
isProcessing,
1919
feeds,
2020
isFeedsLoading,
21+
isBillingAccountExpired,
2122
productsTimelines,
2223
phasesTopics,
2324
location,
@@ -54,7 +55,7 @@ class ProjectDefaultsContainer extends Component {
5455
</MediaQuery>
5556
</TwoColsLayout.Sidebar>
5657
<TwoColsLayout.Content>
57-
<EditProjectDefaultsForm project={this.props.project} />
58+
<EditProjectDefaultsForm project={this.props.project} isBillingAccountExpired={isBillingAccountExpired} />
5859
</TwoColsLayout.Content>
5960
</TwoColsLayout>
6061
)
@@ -68,6 +69,7 @@ const mapStateToProps = ({ loadUser, projectState, projectTopics, topics }) => {
6869

6970
return {
7071
user: loadUser.user,
72+
isBillingAccountExpired: projectState.isBillingAccountExpired,
7173
isProcessing: projectState.processing,
7274
phases: projectState.phases,
7375
phasesNonDirty: projectState.phasesNonDirty,

0 commit comments

Comments
 (0)