Skip to content

Commit 01079dd

Browse files
author
Vikas Agarwal
committed
Merge branch 'release/v1.1.1'
2 parents a56bb91 + a28d10f commit 01079dd

File tree

9 files changed

+70
-9
lines changed

9 files changed

+70
-9
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"fbemitter": "^2.1.1",
4040
"filepicker-js": "^2.4.17",
4141
"filesize": "^3.3.0",
42+
"flat": "^2.0.1",
4243
"formsy-react": "^0.18.1",
4344
"history": "^1.17.0",
4445
"isomorphic-fetch": "^2.2.1",

src/components/ConnectTerms/ConnectTerms.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const ConnectTerms = () => (
88
<h1>Terms</h1>
99
<p>This User Agreement (the "<strong>Agreement</strong>") is a contract between you (referred to herein as "<strong>User</strong>") and Topcoder Inc. ("Topcoder") and applies to User's use and viewing of <a href="http://connect.topcoder.com">connect.topcoder.com</a> and related sub-domains ("<strong>Topcoder Connect</strong>") and all services available through Topcoder Connect (the "<strong>Services</strong>"). By visiting Topcoder Connect, User has accepted this Agreement and has agreed to be bound by the terms of this Agreement. Any Custom Software ordered (as defined below) or Services used through Topcoder Connect are also governed by these Terms. Topcoder may amend this Agreement at any time by posting a revised version on Topcoder Connect. The revised version will be effective at the time Topcoder posts it.</p>
1010
<h2>1. Services and Specifications.</h2>
11-
<p>The Services provide for the creation of certain types of mock-ups, prototypes, and application development of computer software applications (the "<b>Deliverables</b>") through Topcoder's crowdsourcing platform (as defined below) through a Topcoder representative or co-pilot (referred to herein as a "<b>User Success Manager</b>"), as further described on Topcoder Connect. To utilize the Services, User has provided specifications with respect to the Deliverables in reasonable detail as prompted in several fields on webpages associated with Topcoder Connect where the User was requested to enter information regarding the intended Deliverable (such information, the "<b>Preliminary Specifications</b>"). After payment of Project Fees (as defined below) associated with the Deliverable, a User Success Manager shall contact User to gather additional information regarding the Deliverables, as may be necessary in Topcoder's sole discretion. Topcoder and User shall mutually agree on a final set of specifications, which shall be referred to herein as the "<b>Specifications</b>". To the extent the parties are not able to reach agreement on the Specifications, including, but not limited to situations where the information provided by User is insufficient to create Specifications or the Preliminary Specifications are outside the scope of the services described on Topcoder Connect, Topcoder shall refund to User any Project Fees paid by User and Topcoder shall have no further liability or obligations under this Agreement.</p>
11+
<p>The Services provide for the creation of certain types of mock-ups, prototypes, and application development of computer software applications (the "<b>Deliverables</b>") through Topcoder's crowdsourcing platform (as defined below) through a Topcoder representative or co-pilot (referred to herein as a "<b>User Success Manager</b>"), as further described on Topcoder Connect. To utilize the Services, User has provided specifications with respect to the Deliverables in reasonable detail as prompted in several fields on webpages associated with Topcoder Connect where the User was requested to enter information regarding the intended Deliverable (such information, the "<b>Preliminary Specifications</b>"). After payment of Project Fees (as defined below) associated with the Deliverable, a User Success Manager shall contact User to gather additional information regarding the Deliverables, as may be necessary in Topcoder's sole discretion. Topcoder and User shall mutually agree on a final set of specifications, which shall be referred to herein as the "<b>Specifications</b>". As part of this process, Topcoder may provide services to User on an hourly basis. To the extent the parties are not able to reach agreement on the Specifications, including, but not limited to situations where the information provided by User is insufficient to create Specifications or the Preliminary Specifications are outside the scope of the services described on Topcoder Connect, Topcoder shall refund to User any Project Fees paid by User (excluding fees associated with hourly services previously provided) and Topcoder shall have no further liability or obligations under this Agreement.</p>
1212
<h2>2. Definitions.</h2>
1313
<p>For the purposes of this Agreement, the following capitalized terms have the meanings assigned to them in this Section 2. Any capitalized terms used in this Agreement but not otherwise defined in this Section shall have the meanings assigned to them elsewhere in this Agreement.</p>
1414
<ul>

src/components/TextInput/TextInput.scss

+5
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@
4545
border-bottom: 1px solid $tc-gray-40;
4646
color: $tc-gray-30;
4747
}
48+
&.error{
49+
border-left: 3px solid $tc-red-70!important;
50+
border-bottom: 1px solid $tc-red-70!important;
51+
background: $tc-gray-neutral-light!important;
52+
}
4853
}
4954

5055
.input-lg,

src/config/constants.js

+3
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ export const UPDATE_PROJECT_PENDING = 'UPDATE_PROJECT_PENDING'
100100
export const UPDATE_PROJECT_SUCCESS = 'UPDATE_PROJECT_SUCCESS'
101101
export const UPDATE_PROJECT_FAILURE = 'UPDATE_PROJECT_FAILURE'
102102

103+
export const PROJECT_DIRTY = 'PROJECT_DIRTY'
104+
export const PROJECT_DIRTY_UNDO = 'PROJECT_DIRTY_UNDO'
105+
103106
export const LOAD_MEMBERS = 'LOAD_MEMBERS'
104107
export const LOAD_MEMBERS_PENDING = 'LOAD_MEMBERS_PENDING'
105108
export const LOAD_MEMBERS_SUCCESS = 'LOAD_MEMBERS_SUCCESS'

src/projects/actions/project.js

+19-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { getProjectById, createProject as createProjectAPI,
33
deleteProject as deleteProjectAPI,
44
getDirectProjectData } from '../../api/projects'
55
import { LOAD_PROJECT, CREATE_PROJECT, CLEAR_LOADED_PROJECT, UPDATE_PROJECT,
6-
LOAD_DIRECT_PROJECT, DELETE_PROJECT } from '../../config/constants'
6+
LOAD_DIRECT_PROJECT, DELETE_PROJECT, PROJECT_DIRTY, PROJECT_DIRTY_UNDO } from '../../config/constants'
77

88

99
export function loadProject(projectId) {
@@ -58,3 +58,21 @@ export function loadDirectProjectData(directProjectId) {
5858
})
5959
}
6060
}
61+
62+
export function fireProjectDirty(dirtyProject) {
63+
return (dispatch) => {
64+
return dispatch({
65+
type: PROJECT_DIRTY,
66+
payload: dirtyProject
67+
68+
})
69+
}
70+
}
71+
72+
export function fireProjectDirtyUndo() {
73+
return (dispatch) => {
74+
return dispatch({
75+
type: PROJECT_DIRTY_UNDO
76+
})
77+
}
78+
}

src/projects/detail/components/EditProjectForm.jsx

+19-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class EditProjectForm extends Component {
2020
this.onFeaturesSaveAttachedClick = this.onFeaturesSaveAttachedClick.bind(this)
2121
this.submit = this.submit.bind(this)
2222
this.onLeave = this.onLeave.bind(this)
23+
this.handleChange = this.handleChange.bind(this)
2324
}
2425

2526
componentWillMount() {
@@ -33,6 +34,8 @@ class EditProjectForm extends Component {
3334
}
3435

3536
componentWillReceiveProps(nextProps) {
37+
// we receipt property updates from PROJECT_DIRTY REDUX state
38+
if (nextProps.project.isDirty) return
3639
let updatedProject = Object.assign({}, nextProps.project)
3740
if (this.state.isFeaturesDirty && !this.state.isSaving) {
3841
updatedProject = update(updatedProject, {
@@ -59,6 +62,7 @@ class EditProjectForm extends Component {
5962
}
6063

6164
componentWillUnmount() {
65+
this.props.fireProjectDirtyUndo()
6266
window.removeEventListener('beforeunload', this.onLeave)
6367
}
6468

@@ -131,6 +135,17 @@ class EditProjectForm extends Component {
131135
this.props.submitHandler(model)
132136
}
133137

138+
/**
139+
* Handles the change event of the form.
140+
*
141+
* @param change changed form model in flattened form
142+
* @param isChanged flag that indicates if form actually changed from initial model values
143+
*/
144+
handleChange(change) {
145+
// removed check for isChanged argument to fire the PROJECT_DIRTY event for every change in the form
146+
this.props.fireProjectDirty(change)
147+
}
148+
134149

135150
render() {
136151
const { isEdittable, sections } = this.props
@@ -165,6 +180,7 @@ class EditProjectForm extends Component {
165180
onInvalid={this.disableButton}
166181
onValid={this.enableButton}
167182
onValidSubmit={this.submit}
183+
onChange={ this.handleChange }
168184
>
169185
{sections.map(renderSection)}
170186
</Formsy.Form>
@@ -192,7 +208,9 @@ EditProjectForm.propTypes = {
192208
saving: PropTypes.bool.isRequired,
193209
sections: PropTypes.arrayOf(PropTypes.object).isRequired,
194210
isEdittable: PropTypes.bool.isRequired,
195-
submitHandler: PropTypes.func.isRequired
211+
submitHandler: PropTypes.func.isRequired,
212+
fireProjectDirty: PropTypes.func.isRequired,
213+
fireProjectDirtyUndo: PropTypes.func.isRequired
196214
}
197215

198216
export default withRouter(EditProjectForm)

src/projects/detail/containers/ProjectInfoContainer.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ class ProjectInfoContainer extends React.Component {
124124
if (project.directProjectId) {
125125
directLinks.push({name: 'Project in Topcoder Direct', href: `${DIRECT_PROJECT_URL}${project.directProjectId}`})
126126
} else {
127-
directLinks.push({name: 'No Direct project created. Please contact support.', href: 'mailto:[email protected]'})
127+
directLinks.push({name: 'Direct project not linked. Contact support.', href: 'mailto:[email protected]'})
128128
}
129129
directLinks.push({name: 'Salesforce Lead', href: `${SALESFORCE_PROJECT_LEAD_LINK}${project.id}`})
130130
}

src/projects/detail/containers/SpecificationContainer.jsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import Sticky from 'react-stickynode'
88
import ProjectSpecSidebar from '../components/ProjectSpecSidebar'
99
import FooterV2 from '../../../components/FooterV2/FooterV2'
1010
import EditProjectForm from '../components/EditProjectForm'
11-
import { updateProject } from '../../actions/project'
11+
import { updateProject, fireProjectDirty, fireProjectDirtyUndo } from '../../actions/project'
1212
import spinnerWhileLoading from '../../../components/LoadingSpinner'
1313
// import { Icons } from 'appirio-tech-react-components'
1414
import typeToSpecification from '../../../config/projectSpecification/typeToSpecification'
@@ -73,6 +73,8 @@ class SpecificationContainer extends Component {
7373
submitHandler={this.saveProject}
7474
saving={processing}
7575
route={this.props.route}
76+
fireProjectDirty={ this.props.fireProjectDirty }
77+
fireProjectDirtyUndo= { this.props.fireProjectDirtyUndo }
7678
/>
7779
</div>
7880

@@ -100,6 +102,6 @@ const mapStateToProps = ({projectState, loadUser}) => {
100102
}
101103
}
102104

103-
const mapDispatchToProps = { updateProject }
105+
const mapDispatchToProps = { updateProject, fireProjectDirty, fireProjectDirtyUndo }
104106

105107
export default connect(mapStateToProps, mapDispatchToProps)(SpecificationContainer)

src/projects/reducers/project.js

+17-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
1+
import { unflatten } from 'flat'
22
import {
33
LOAD_PROJECT_PENDING, LOAD_PROJECT_SUCCESS, LOAD_PROJECT_FAILURE, LOAD_DIRECT_PROJECT_SUCCESS,
44
CREATE_PROJECT_PENDING, CREATE_PROJECT_SUCCESS, CREATE_PROJECT_FAILURE, CLEAR_LOADED_PROJECT,
@@ -10,7 +10,7 @@ import {
1010
ADD_PROJECT_MEMBER_PENDING, ADD_PROJECT_MEMBER_SUCCESS, ADD_PROJECT_MEMBER_FAILURE,
1111
UPDATE_PROJECT_MEMBER_PENDING, UPDATE_PROJECT_MEMBER_SUCCESS, UPDATE_PROJECT_MEMBER_FAILURE,
1212
REMOVE_PROJECT_MEMBER_PENDING, REMOVE_PROJECT_MEMBER_SUCCESS, REMOVE_PROJECT_MEMBER_FAILURE,
13-
GET_PROJECTS_SUCCESS
13+
GET_PROJECTS_SUCCESS, PROJECT_DIRTY, PROJECT_DIRTY_UNDO
1414
} from '../../config/constants'
1515
import _ from 'lodash'
1616
import update from 'react-addons-update'
@@ -47,6 +47,7 @@ export const projectState = function (state=initialState, action) {
4747
return Object.assign({}, state, {
4848
isLoading: false,
4949
project: action.payload,
50+
projectNonDirty: _.cloneDeep(action.payload),
5051
lastUpdated: new Date()
5152
})
5253

@@ -87,7 +88,8 @@ export const projectState = function (state=initialState, action) {
8788
return Object.assign({}, state, {
8889
processing: false,
8990
error: false,
90-
project: action.payload
91+
project: action.payload,
92+
projectNonDirty: _.cloneDeep(action.payload)
9193
})
9294

9395
case DELETE_PROJECT_SUCCESS:
@@ -167,6 +169,18 @@ export const projectState = function (state=initialState, action) {
167169
})
168170
}
169171

172+
case PROJECT_DIRTY: {
173+
return Object.assign({}, state, {
174+
project: _.merge({}, state.project, unflatten(action.payload), { isDirty : true})
175+
})
176+
}
177+
178+
case PROJECT_DIRTY_UNDO: {
179+
return Object.assign({}, state, {
180+
project: _.cloneDeep(state.projectNonDirty)
181+
})
182+
}
183+
170184
case LOAD_PROJECT_FAILURE:
171185
case CREATE_PROJECT_FAILURE:
172186
case DELETE_PROJECT_FAILURE:

0 commit comments

Comments
 (0)