From 2e8d91db8db3aae70db6b6ee4d3f7c074f1b67f5 Mon Sep 17 00:00:00 2001 From: yoution Date: Mon, 31 May 2021 11:09:09 +0800 Subject: [PATCH 1/2] TC Billing Account Enhancement --- src/actions/projects.js | 10 +++++++- .../ChallengeEditor.module.scss | 5 ++++ .../ChallengeView/ChallengeView.module.scss | 5 ++++ .../ChallengeEditor/ChallengeView/index.js | 3 +++ src/components/ChallengeEditor/index.js | 3 +++ src/config/constants.js | 6 +++++ src/containers/ChallengeEditor/index.js | 6 +++++ src/containers/Challenges/index.js | 1 - src/reducers/projects.js | 25 ++++++++++++++++++- src/services/projects.js | 12 +++++++++ 10 files changed, 73 insertions(+), 3 deletions(-) diff --git a/src/actions/projects.js b/src/actions/projects.js index cd93004e..13f542dc 100644 --- a/src/actions/projects.js +++ b/src/actions/projects.js @@ -1,8 +1,9 @@ import { + LOAD_PROJECT_BILLING_ACCOUNT, LOAD_CHALLENGE_MEMBERS_SUCCESS, LOAD_PROJECT_DETAILS } from '../config/constants' -import { fetchProjectById } from '../services/projects' +import { fetchProjectById, fetchBillingAccount } from '../services/projects' /** * Loads project details @@ -19,6 +20,13 @@ export function loadProject (projectId) { members }) } + + // Loads billing account + dispatch({ + type: LOAD_PROJECT_BILLING_ACCOUNT, + payload: fetchBillingAccount(projectId) + }) + return project }) }) diff --git a/src/components/ChallengeEditor/ChallengeEditor.module.scss b/src/components/ChallengeEditor/ChallengeEditor.module.scss index 51ba1127..79366ade 100644 --- a/src/components/ChallengeEditor/ChallengeEditor.module.scss +++ b/src/components/ChallengeEditor/ChallengeEditor.module.scss @@ -414,6 +414,11 @@ } } +.expiredMessage { + margin-left: 20px; + color: $red; +} + .bottomContainer { display: inline-flex; justify-content: space-between; diff --git a/src/components/ChallengeEditor/ChallengeView/ChallengeView.module.scss b/src/components/ChallengeEditor/ChallengeView/ChallengeView.module.scss index df8cc001..2ed1d915 100644 --- a/src/components/ChallengeEditor/ChallengeView/ChallengeView.module.scss +++ b/src/components/ChallengeEditor/ChallengeView/ChallengeView.module.scss @@ -255,6 +255,11 @@ } } +.expiredMessage { + margin-left: 20px; + color: $red; +} + .button { height: 40px; span { diff --git a/src/components/ChallengeEditor/ChallengeView/index.js b/src/components/ChallengeEditor/ChallengeView/index.js index 1d25750b..6ae3e3ed 100644 --- a/src/components/ChallengeEditor/ChallengeView/index.js +++ b/src/components/ChallengeEditor/ChallengeView/index.js @@ -31,6 +31,7 @@ const ChallengeView = ({ projectDetail, challenge, attachments, + isBillingAccountExpired, metadata, challengeResources, token, @@ -197,6 +198,7 @@ const ChallengeView = ({ Billing Account Id: {projectDetail.billingAccountId} + {isBillingAccountExpired && Expired} {isBetaMode() && ( @@ -278,6 +280,7 @@ ChallengeView.propTypes = { }).isRequired, projectDetail: PropTypes.object, challenge: PropTypes.object, + isBillingAccountExpired: PropTypes.bool, attachments: PropTypes.array, metadata: PropTypes.object, token: PropTypes.string, diff --git a/src/components/ChallengeEditor/index.js b/src/components/ChallengeEditor/index.js index 5ea47246..76223c11 100644 --- a/src/components/ChallengeEditor/index.js +++ b/src/components/ChallengeEditor/index.js @@ -1181,6 +1181,7 @@ class ChallengeEditor extends Component { } = this.state const { isNew, + isBillingAccountExpired, isLoading, metadata, uploadAttachments, @@ -1483,6 +1484,7 @@ class ChallengeEditor extends Component { Billing Account Id: {projectDetail.billingAccountId} + {isBillingAccountExpired && Expired} {isBetaMode() && ( @@ -1606,6 +1608,7 @@ ChallengeEditor.propTypes = { projectDetail: PropTypes.object, challengeResources: PropTypes.arrayOf(PropTypes.object), isNew: PropTypes.bool.isRequired, + isBillingAccountExpired: PropTypes.bool, projectId: PropTypes.string.isRequired, challengeId: PropTypes.string, metadata: PropTypes.object.isRequired, diff --git a/src/config/constants.js b/src/config/constants.js index 014f7024..4fa3ef79 100644 --- a/src/config/constants.js +++ b/src/config/constants.js @@ -44,6 +44,12 @@ export const LOAD_PROJECTS_SUCCESS = 'LOAD_PROJECTS_SUCCESS' export const LOAD_PROJECTS_PENDING = 'LOAD_PROJECTS_PENDING' export const LOAD_PROJECTS_FAILURE = 'LOAD_PROJECTS_FAILURE' +// project billingAccount +export const LOAD_PROJECT_BILLING_ACCOUNT = 'LOAD_PROJECT_BILLING_ACCOUNT' +export const LOAD_PROJECT_BILLING_ACCOUNT_PENDING = 'LOAD_PROJECT_BILLING_ACCOUNT_PENDING' +export const LOAD_PROJECT_BILLING_ACCOUNT_FAILURE = 'LOAD_PROJECT_BILLING_ACCOUNT_FAILURE' +export const LOAD_PROJECT_BILLING_ACCOUNT_SUCCESS = 'LOAD_PROJECT_BILLING_ACCOUNT_SUCCESS' + export const SET_ACTIVE_PROJECT = 'SET_ACTIVE_PROJECT' export const LOAD_USER_SUCCESS = 'LOAD_USER_SUCCESS' diff --git a/src/containers/ChallengeEditor/index.js b/src/containers/ChallengeEditor/index.js index 99fb54f5..cbe144b1 100644 --- a/src/containers/ChallengeEditor/index.js +++ b/src/containers/ChallengeEditor/index.js @@ -236,6 +236,7 @@ class ChallengeEditor extends Component { const { match, isLoading, + isBillingAccountExpired, isProjectLoading, // challengeDetails, challengeResources, @@ -316,6 +317,7 @@ class ChallengeEditor extends Component { (( (( ({ activeProjectId: sidebar.activeProjectId, projects: sidebar.projects, projectDetail: projects.projectDetail - }) const mapDispatchToProps = { diff --git a/src/reducers/projects.js b/src/reducers/projects.js index f80e9a93..01cac31b 100644 --- a/src/reducers/projects.js +++ b/src/reducers/projects.js @@ -3,6 +3,9 @@ */ import _ from 'lodash' import { + LOAD_PROJECT_BILLING_ACCOUNT_PENDING, + LOAD_PROJECT_BILLING_ACCOUNT_SUCCESS, + LOAD_PROJECT_BILLING_ACCOUNT_FAILURE, LOAD_PROJECT_DETAILS_FAILURE, LOAD_PROJECT_DETAILS_PENDING, LOAD_PROJECT_DETAILS_SUCCESS @@ -10,7 +13,9 @@ import { const initialState = { isLoading: false, - projectDetail: {} + projectDetail: {}, + isBillingAccountExpired: false, + isBillingAccountLoading: false } export default function (state = initialState, action) { @@ -28,6 +33,24 @@ export default function (state = initialState, action) { hasProjectAccess: true, isLoading: false } + case LOAD_PROJECT_BILLING_ACCOUNT_PENDING: + return { + ...state, + isBillingAccountLoading: true, + isBillingAccountExpired: false + } + case LOAD_PROJECT_BILLING_ACCOUNT_SUCCESS: + return { + ...state, + isBillingAccountLoading: false, + isBillingAccountExpired: !action.payload.active + } + case LOAD_PROJECT_BILLING_ACCOUNT_FAILURE: + return { + ...state, + isBillingAccountLoading: false, + isBillingAccountExpired: false + } default: return state } diff --git a/src/services/projects.js b/src/services/projects.js index 3ac4bafe..70711cf6 100644 --- a/src/services/projects.js +++ b/src/services/projects.js @@ -3,6 +3,18 @@ import { axiosInstance } from './axiosWithAuth' import * as queryString from 'query-string' const { PROJECT_API_URL } = process.env +/** + * Get billing account based on project id + * + * @param {String} projectId Id of the project + * + * @returns {Promise} Billing account data + */ +export async function fetchBillingAccount (projectId) { + const response = await axiosInstance.get(`${PROJECT_API_URL}/${projectId}/billingAccount`) + return _.get(response, 'data') +} + /** * Api request for fetching member's projects * @returns {Promise<*>} From 51c29488e20aef92b410c38ca3325719617d242b Mon Sep 17 00:00:00 2001 From: Vikas Agarwal Date: Tue, 1 Jun 2021 11:19:49 +0530 Subject: [PATCH 2/2] git#1154-Prevent activation of challenge when BA associated to the project is not active - preventing activation instead of just showing the expired symbol --- src/components/ChallengeEditor/index.js | 7 ++++++- .../ChallengesComponent/ChallengeCard/index.js | 12 +++++++++--- .../ChallengesComponent/ChallengeList/index.js | 7 +++++-- src/components/ChallengesComponent/index.js | 7 +++++-- src/containers/ChallengeEditor/index.js | 7 ++++++- src/containers/Challenges/index.js | 10 +++++++--- 6 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/components/ChallengeEditor/index.js b/src/components/ChallengeEditor/index.js index 76223c11..2d4bdef7 100644 --- a/src/components/ChallengeEditor/index.js +++ b/src/components/ChallengeEditor/index.js @@ -655,7 +655,11 @@ class ChallengeEditor extends Component { toggleLaunch (e) { e.preventDefault() if (this.validateChallenge()) { - this.setState({ isLaunch: true }) + if (!this.props.isBillingAccountExpired) { + this.setState({ isLaunch: true }) + } else { + this.setState({ isLaunch: true, error: 'Unable to activate challenge as Billing Account is not active.' }) + } } } @@ -1279,6 +1283,7 @@ class ChallengeEditor extends Component { errorMessage={this.state.error} onCancel={this.resetModal} onConfirm={this.onActiveChallenge} + disableConfirmButton={isBillingAccountExpired} /> ) } diff --git a/src/components/ChallengesComponent/ChallengeCard/index.js b/src/components/ChallengesComponent/ChallengeCard/index.js index 5a1258ae..4a0695a2 100644 --- a/src/components/ChallengesComponent/ChallengeCard/index.js +++ b/src/components/ChallengesComponent/ChallengeCard/index.js @@ -209,7 +209,11 @@ class ChallengeCard extends React.Component { onUpdateLaunch () { if (!this.state.isLaunch) { - this.setState({ isLaunch: true }) + if (!this.props.isBillingAccountExpired) { + this.setState({ isLaunch: true }) + } else { + this.setState({ isLaunch: true, error: 'Unable to activate challenge as Billing Account is not active.' }) + } } } @@ -272,7 +276,7 @@ class ChallengeCard extends React.Component { render () { const { isLaunch, isConfirm, isSaving, isDeleteLaunch, isCheckChalengePermission, hasEditChallengePermission } = this.state - const { challenge, shouldShowCurrentPhase, reloadChallengeList } = this.props + const { challenge, shouldShowCurrentPhase, reloadChallengeList, isBillingAccountExpired } = this.props const { phaseMessage, endTime } = getPhaseInfo(challenge) const deleteMessage = isCheckChalengePermission ? 'Checking permissions...' @@ -305,6 +309,7 @@ class ChallengeCard extends React.Component { errorMessage={this.state.error} onCancel={this.resetModal} onConfirm={this.onLaunchChallenge} + disableConfirmButton={isBillingAccountExpired} /> ) } @@ -364,7 +369,8 @@ ChallengeCard.propTypes = { shouldShowCurrentPhase: PropTypes.bool, reloadChallengeList: PropTypes.func, partiallyUpdateChallengeDetails: PropTypes.func.isRequired, - deleteChallenge: PropTypes.func.isRequired + deleteChallenge: PropTypes.func.isRequired, + isBillingAccountExpired: PropTypes.bool } export default withRouter(ChallengeCard) diff --git a/src/components/ChallengesComponent/ChallengeList/index.js b/src/components/ChallengesComponent/ChallengeList/index.js index 941c27eb..e7c355a2 100644 --- a/src/components/ChallengesComponent/ChallengeList/index.js +++ b/src/components/ChallengesComponent/ChallengeList/index.js @@ -103,7 +103,8 @@ class ChallengeList extends Component { perPage, totalChallenges, partiallyUpdateChallengeDetails, - deleteChallenge + deleteChallenge, + isBillingAccountExpired } = this.props if (warnMessage) { return @@ -215,6 +216,7 @@ class ChallengeList extends Component { reloadChallengeList={this.reloadChallengeList} partiallyUpdateChallengeDetails={partiallyUpdateChallengeDetails} deleteChallenge={deleteChallenge} + isBillingAccountExpired={isBillingAccountExpired} /> ) @@ -258,7 +260,8 @@ ChallengeList.propTypes = { perPage: PropTypes.number.isRequired, totalChallenges: PropTypes.number.isRequired, partiallyUpdateChallengeDetails: PropTypes.func.isRequired, - deleteChallenge: PropTypes.func.isRequired + deleteChallenge: PropTypes.func.isRequired, + isBillingAccountExpired: PropTypes.bool } export default ChallengeList diff --git a/src/components/ChallengesComponent/index.js b/src/components/ChallengesComponent/index.js index eb386d49..d96f9850 100644 --- a/src/components/ChallengesComponent/index.js +++ b/src/components/ChallengesComponent/index.js @@ -27,7 +27,8 @@ const ChallengesComponent = ({ perPage, totalChallenges, partiallyUpdateChallengeDetails, - deleteChallenge + deleteChallenge, + isBillingAccountExpired }) => { return ( @@ -88,6 +89,7 @@ const ChallengesComponent = ({ totalChallenges={totalChallenges} partiallyUpdateChallengeDetails={partiallyUpdateChallengeDetails} deleteChallenge={deleteChallenge} + isBillingAccountExpired={isBillingAccountExpired} /> )} @@ -112,7 +114,8 @@ ChallengesComponent.propTypes = { perPage: PropTypes.number.isRequired, totalChallenges: PropTypes.number.isRequired, partiallyUpdateChallengeDetails: PropTypes.func.isRequired, - deleteChallenge: PropTypes.func.isRequired + deleteChallenge: PropTypes.func.isRequired, + isBillingAccountExpired: PropTypes.bool } ChallengesComponent.defaultProps = { diff --git a/src/containers/ChallengeEditor/index.js b/src/containers/ChallengeEditor/index.js index cbe144b1..3be5fd34 100644 --- a/src/containers/ChallengeEditor/index.js +++ b/src/containers/ChallengeEditor/index.js @@ -148,7 +148,11 @@ class ChallengeEditor extends Component { } onLaunchChallenge () { - this.setState({ showLaunchModal: true }) + if (!this.props.isBillingAccountExpired) { + this.setState({ showLaunchModal: true }) + } else { + this.setState({ showLaunchModal: true, launchError: 'Unable to activate challenge as Billing Account is not active.' }) + } } onCloseTask () { @@ -289,6 +293,7 @@ class ChallengeEditor extends Component { errorMessage={this.state.launchError} onCancel={this.closeLaunchModal} onConfirm={this.activateChallenge} + disableConfirmButton={isBillingAccountExpired} /> const closeTaskModal = } @@ -176,7 +178,8 @@ Challenges.propTypes = { loadProjects: PropTypes.func.isRequired, setActiveProject: PropTypes.func.isRequired, partiallyUpdateChallengeDetails: PropTypes.func.isRequired, - deleteChallenge: PropTypes.func.isRequired + deleteChallenge: PropTypes.func.isRequired, + isBillingAccountExpired: PropTypes.bool } const mapStateToProps = ({ challenges, sidebar, projects }) => ({ @@ -184,7 +187,8 @@ const mapStateToProps = ({ challenges, sidebar, projects }) => ({ challengeProjectId: challenges.projectId, activeProjectId: sidebar.activeProjectId, projects: sidebar.projects, - projectDetail: projects.projectDetail + projectDetail: projects.projectDetail, + isBillingAccountExpired: projects.isBillingAccountExpired }) const mapDispatchToProps = {