Skip to content

Commit d46442f

Browse files
author
vikasrohit
authored
Merge pull request #1168 from appirio-tech/feature/new-project-wizard-unsaved-content
Added unsaved content alert to new project modal
2 parents 4e2718c + 50076ab commit d46442f

File tree

4 files changed

+47
-21
lines changed

4 files changed

+47
-21
lines changed

src/components/TopBar/ProjectsToolBar.js

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ class ProjectsToolBar extends Component {
2828
constructor(props) {
2929
super(props)
3030
this.state = {
31-
isCreatingProject: false,
3231
isCreateProjectModalVisible : false,
3332
errorCreatingProject: false,
3433
isFilterVisible: false
@@ -41,6 +40,7 @@ class ProjectsToolBar extends Component {
4140
this.handleSearch = this.handleSearch.bind(this)
4241
this.handleMyProjectsFilter = this.handleMyProjectsFilter.bind(this)
4342
this.createProject = this.createProject.bind(this)
43+
this.onLeave = this.onLeave.bind(this)
4444
}
4545

4646
componentWillReceiveProps(nextProps) {
@@ -49,7 +49,7 @@ class ProjectsToolBar extends Component {
4949
if (!nextProps.projectCreationError
5050
&& nextProps.project && nextProps.project.id) {
5151
this.hideCreateProjectDialog()
52-
this.context.router.push('/projects/' + nextProps.project.id)
52+
this.props.router.push('/projects/' + nextProps.project.id)
5353
} else {
5454
this.setState({
5555
errorCreatingProject: true
@@ -58,11 +58,32 @@ class ProjectsToolBar extends Component {
5858
}
5959
}
6060

61+
componentDidMount() {
62+
const { router, route } = this.props
63+
// sets route leave hook to show unsaved changes alert and persist incomplete project
64+
this.routeLeaveHook = router.setRouteLeaveHook(route, this.onLeave)
65+
66+
// sets window unload hook to show unsaved changes alert and persist incomplete project
67+
window.addEventListener('beforeunload', this.onLeave)
68+
}
69+
6170
componentWillUnmount() {
71+
window.removeEventListener('beforeunload', this.onLeave)
72+
if (this.routeLeaveHook) {
73+
this.routeLeaveHook()
74+
}
6275
const contentDiv = document.getElementById('wrapper-main')
6376
contentDiv.classList.remove('with-filters')
6477
}
6578

79+
onLeave(e) {
80+
const { isProjectDirty } = this.state
81+
const { creatingProject } = this.props
82+
if (isProjectDirty && !creatingProject) {
83+
return e.returnValue = 'You have unsaved changes. Are you sure you want to leave?'
84+
}
85+
}
86+
6687
/*eslint-disable no-unused-vars */
6788
handleTermChange(oldTerm, searchTerm, reqNo, callback) {
6889
this.props.projectSuggestions(searchTerm)
@@ -85,10 +106,17 @@ class ProjectsToolBar extends Component {
85106
}
86107

87108
hideCreateProjectDialog() {
88-
this.setState({
89-
isCreateProjectModalVisible : false,
90-
errorCreatingProject: false
91-
})
109+
let confirm = true
110+
if (this.state.isProjectDirty) {
111+
confirm = window.confirm('You have unsaved changes. Are you sure you want to leave?')
112+
}
113+
if (confirm === true) {
114+
this.setState({
115+
isProjectDirty: false,
116+
isCreateProjectModalVisible : false,
117+
errorCreatingProject: false
118+
})
119+
}
92120
}
93121

94122
applyFilters(filter) {
@@ -116,7 +144,7 @@ class ProjectsToolBar extends Component {
116144
routeWithParams(criteria, page) {
117145
// remove any null values
118146
criteria = _.pickBy(criteria, _.identity)
119-
this.context.router.push({
147+
this.props.router.push({
120148
pathname: '/projects/',
121149
query: _.assign({}, criteria, { page })
122150
})
@@ -156,6 +184,12 @@ class ProjectsToolBar extends Component {
156184
createProject={ this.createProject }
157185
closeModal={ this.hideCreateProjectDialog }
158186
userRoles={ userRoles }
187+
onProjectUpdate={ (updatedProject, dirty=true) => {
188+
this.setState({
189+
isProjectDirty: dirty
190+
})
191+
}
192+
}
159193
/>
160194
}
161195
{ errorCreatingProject && <CoderBot code={ 500 } message="Unable to create project" />}
@@ -216,10 +250,6 @@ ProjectsToolBar.propTypes = {
216250
ProjectsToolBar.defaultProps = {
217251
}
218252

219-
ProjectsToolBar.contextTypes = {
220-
router: PropTypes.object.isRequired
221-
}
222-
223253
// export default ProjectsToolBar
224254

225255
const mapStateToProps = ({ projectSearchSuggestions, searchTerm, projectSearch, projectState, loadUser }) => {

src/components/TopBar/TopBarContainer.js

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import React, {PropTypes} from 'react'
1+
import React from 'react'
22
import { connect } from 'react-redux'
3-
import { Link } from 'react-router'
3+
import { Link, withRouter } from 'react-router'
44
import _ from 'lodash'
55
import { UserDropdown, Icons } from 'appirio-tech-react-components'
66
const { ConnectLogo } = Icons
@@ -40,7 +40,7 @@ class TopBarContainer extends React.Component {
4040
const logoutLink = `https://accounts.${DOMAIN}/#!/logout?retUrl=${homePageUrl}`
4141
const isLoggedIn = userRoles && userRoles.length
4242
const logoTargetUrl = isLoggedIn ? '/projects' : '/'
43-
const isHomePage = this.context.router.isActive('/', true)
43+
const isHomePage = this.props.router.isActive('/', true)
4444
// NOTE: hardcoding to connectv2, once connect v1
4545
window.host
4646
const loginUrl = `${ACCOUNTS_APP_LOGIN_URL}?retUrl=${window.location.protocol}//${window.location.host}/`
@@ -108,10 +108,6 @@ class TopBarContainer extends React.Component {
108108
}
109109
}
110110

111-
TopBarContainer.contextTypes = {
112-
router: PropTypes.object.isRequired
113-
}
114-
115111
const mapStateToProps = ({ loadUser }) => {
116112
return {
117113
userRoles : _.get(loadUser, 'user.roles', []),
@@ -121,4 +117,4 @@ const mapStateToProps = ({ loadUser }) => {
121117

122118
const actionsToBind = { }
123119

124-
export default connect(mapStateToProps, actionsToBind)(TopBarContainer)
120+
export default withRouter(connect(mapStateToProps, actionsToBind)(TopBarContainer))

src/projects/routes.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { requiresAuthentication } from '../components/AuthenticatedComponent'
1414

1515

1616
const projectRoutes = (
17-
<Route path="/projects" components={ { topbar: (props) => <TopBarContainer toolbar={ props.toolbar } shortUserMenu={ props.shortUserMenu } />, content: requiresAuthentication(ProjectLayout)}}>
17+
<Route path="/projects" components={ { topbar: (props) => <TopBarContainer route={ props.route } toolbar={ props.toolbar } shortUserMenu={ props.shortUserMenu } />, content: requiresAuthentication(ProjectLayout)}}>
1818
// TODO add project topbar
1919
<IndexRoute components={{toolbar: ProjectsToolBar, main: Projects }} />
2020
<Route path=":projectId" components={{toolbar: ProjectToolBar, main: ProjectDetail }} >

src/routes.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ const validateCreateProjectParams = (nextState, replace, callback) => {
9696
callback()
9797
}
9898

99-
const renderTopBarWithProjectsToolBar = () => <TopBarContainer toolbar={ ProjectsToolBar } />
99+
const renderTopBarWithProjectsToolBar = (props) => <TopBarContainer toolbar={ ProjectsToolBar } route={props.route} />
100100

101101
export default (
102102
<Route path="/" onUpdate={() => window.scrollTo(0, 0)} component={ App } onEnter={ redirectToConnect }>

0 commit comments

Comments
 (0)