@@ -2,7 +2,7 @@ import { browserHistory } from 'react-router';
2
2
import axios from 'axios' ;
3
3
import objectID from 'bson-objectid' ;
4
4
import each from 'async/each' ;
5
- import { isEqual , pick } from 'lodash' ;
5
+ import isEqual from 'lodash/isEqual ' ;
6
6
import * as ActionTypes from '../../../constants' ;
7
7
import { showToast , setToastText } from './toast' ;
8
8
import {
@@ -32,6 +32,22 @@ export function setProjectName(name) {
32
32
} ;
33
33
}
34
34
35
+ export function projectSaveFail ( error ) {
36
+ return {
37
+ type : ActionTypes . PROJECT_SAVE_FAIL ,
38
+ error
39
+ } ;
40
+ }
41
+
42
+ export function setNewProject ( project ) {
43
+ return {
44
+ type : ActionTypes . NEW_PROJECT ,
45
+ project,
46
+ owner : project . user ,
47
+ files : project . files
48
+ } ;
49
+ }
50
+
35
51
export function getProject ( id ) {
36
52
return ( dispatch , getState ) => {
37
53
dispatch ( justOpenedProject ( ) ) ;
@@ -66,37 +82,71 @@ export function clearPersistedState() {
66
82
} ;
67
83
}
68
84
85
+ export function startSavingProject ( ) {
86
+ return {
87
+ type : ActionTypes . START_SAVING_PROJECT
88
+ } ;
89
+ }
90
+
91
+ export function endSavingProject ( ) {
92
+ return {
93
+ type : ActionTypes . END_SAVING_PROJECT
94
+ } ;
95
+ }
96
+
97
+ export function projectSaveSuccess ( ) {
98
+ return {
99
+ type : ActionTypes . PROJECT_SAVE_SUCCESS
100
+ } ;
101
+ }
102
+
103
+ // want a function that will check for changes on the front end
104
+ function getSynchedProject ( currentState , responseProject ) {
105
+ let hasChanges = false ;
106
+ const synchedProject = Object . assign ( { } , responseProject ) ;
107
+ const currentFiles = currentState . files . map ( ( { name, children, content } ) => ( { name, children, content } ) ) ;
108
+ const responseFiles = responseProject . files . map ( ( { name, children, content } ) => ( { name, children, content } ) ) ;
109
+ if ( ! isEqual ( currentFiles , responseFiles ) ) {
110
+ synchedProject . files = currentState . files ;
111
+ hasChanges = true ;
112
+ }
113
+ if ( currentState . project . name !== responseProject . name ) {
114
+ synchedProject . name = currentState . project . name ;
115
+ hasChanges = true ;
116
+ }
117
+ return {
118
+ synchedProject,
119
+ hasChanges
120
+ } ;
121
+ }
122
+
69
123
export function saveProject ( selectedFile = null , autosave = false ) {
70
124
return ( dispatch , getState ) => {
71
125
const state = getState ( ) ;
126
+ if ( state . project . isSaving ) {
127
+ return Promise . resolve ( ) ;
128
+ }
129
+ dispatch ( startSavingProject ( ) ) ;
72
130
if ( state . user . id && state . project . owner && state . project . owner . id !== state . user . id ) {
73
131
return Promise . reject ( ) ;
74
132
}
75
133
const formParams = Object . assign ( { } , state . project ) ;
76
134
formParams . files = [ ...state . files ] ;
77
135
if ( selectedFile ) {
78
- console . log ( 'selected file being updated' ) ;
79
136
const fileToUpdate = formParams . files . find ( file => file . id === selectedFile . id ) ;
80
137
fileToUpdate . content = selectedFile . content ;
81
138
}
82
139
if ( state . project . id ) {
83
140
return axios . put ( `${ ROOT_URL } /projects/${ state . project . id } ` , formParams , { withCredentials : true } )
84
141
. then ( ( response ) => {
85
- const currentState = getState ( ) ;
86
- const savedProject = Object . assign ( { } , response . data ) ;
87
- if ( ! isEqual (
88
- pick ( currentState . files , [ 'name' , 'children' , 'content' ] ) ,
89
- pick ( response . data . files , [ 'name' , 'children' , 'content' ] )
90
- ) ) {
91
- savedProject . files = currentState . files ;
142
+ dispatch ( endSavingProject ( ) ) ;
143
+ dispatch ( setUnsavedChanges ( false ) ) ;
144
+ const { hasChanges, synchedProject } = getSynchedProject ( getState ( ) , response . data ) ;
145
+ if ( hasChanges ) {
92
146
dispatch ( setUnsavedChanges ( true ) ) ;
93
- } else {
94
- dispatch ( setUnsavedChanges ( false ) ) ;
95
147
}
96
- dispatch ( setProject ( savedProject ) ) ;
97
- dispatch ( {
98
- type : ActionTypes . PROJECT_SAVE_SUCCESS
99
- } ) ;
148
+ dispatch ( setProject ( synchedProject ) ) ;
149
+ dispatch ( projectSaveSuccess ( ) ) ;
100
150
if ( ! autosave ) {
101
151
if ( state . ide . justOpenedProject && state . preferences . autosave ) {
102
152
dispatch ( showToast ( 5500 ) ) ;
@@ -110,30 +160,32 @@ export function saveProject(selectedFile = null, autosave = false) {
110
160
}
111
161
} )
112
162
. catch ( ( response ) => {
163
+ dispatch ( endSavingProject ( ) ) ;
113
164
if ( response . status === 403 ) {
114
165
dispatch ( showErrorModal ( 'staleSession' ) ) ;
115
166
} else if ( response . status === 409 ) {
116
167
dispatch ( showErrorModal ( 'staleProject' ) ) ;
117
168
} else {
118
- dispatch ( {
119
- type : ActionTypes . PROJECT_SAVE_FAIL ,
120
- error : response . data
121
- } ) ;
169
+ dispatch ( projectSaveFail ( response . data ) ) ;
122
170
}
123
171
} ) ;
124
172
}
125
173
126
174
return axios . post ( `${ ROOT_URL } /projects` , formParams , { withCredentials : true } )
127
175
. then ( ( response ) => {
128
- dispatch ( setUnsavedChanges ( false ) ) ;
129
- dispatch ( setProject ( response . data ) ) ;
130
- browserHistory . push ( `/${ response . data . user . username } /sketches/${ response . data . id } ` ) ;
131
- dispatch ( {
132
- type : ActionTypes . NEW_PROJECT ,
133
- project : response . data ,
134
- owner : response . data . user ,
135
- files : response . data . files
136
- } ) ;
176
+ dispatch ( endSavingProject ( ) ) ;
177
+ const { hasChanges, synchedProject } = getSynchedProject ( getState ( ) , response . data ) ;
178
+ if ( hasChanges ) {
179
+ dispatch ( setNewProject ( synchedProject ) ) ;
180
+ dispatch ( setUnsavedChanges ( false ) ) ;
181
+ browserHistory . push ( `/${ response . data . user . username } /sketches/${ response . data . id } ` ) ;
182
+ dispatch ( setUnsavedChanges ( true ) ) ;
183
+ } else {
184
+ dispatch ( setNewProject ( synchedProject ) ) ;
185
+ dispatch ( setUnsavedChanges ( false ) ) ;
186
+ browserHistory . push ( `/${ response . data . user . username } /sketches/${ response . data . id } ` ) ;
187
+ }
188
+ dispatch ( projectSaveSuccess ( ) ) ;
137
189
if ( ! autosave ) {
138
190
if ( state . preferences . autosave ) {
139
191
dispatch ( showToast ( 5500 ) ) ;
@@ -147,13 +199,11 @@ export function saveProject(selectedFile = null, autosave = false) {
147
199
}
148
200
} )
149
201
. catch ( ( response ) => {
202
+ dispatch ( endSavingProject ( ) ) ;
150
203
if ( response . status === 403 ) {
151
204
dispatch ( showErrorModal ( 'staleSession' ) ) ;
152
205
} else {
153
- dispatch ( {
154
- type : ActionTypes . PROJECT_SAVE_FAIL ,
155
- error : response . data
156
- } ) ;
206
+ dispatch ( projectSaveFail ( response . data ) ) ;
157
207
}
158
208
} ) ;
159
209
} ;
@@ -166,22 +216,28 @@ export function autosaveProject() {
166
216
}
167
217
168
218
export function createProject ( ) {
169
- return ( dispatch ) => {
219
+ return ( dispatch , getState ) => {
220
+ const state = getState ( ) ;
221
+ if ( state . project . isSaving ) {
222
+ Promise . resolve ( ) ;
223
+ return ;
224
+ }
225
+ dispatch ( startSavingProject ( ) ) ;
170
226
axios . post ( `${ ROOT_URL } /projects` , { } , { withCredentials : true } )
171
227
. then ( ( response ) => {
172
- browserHistory . push ( `/${ response . data . user . username } /sketches/${ response . data . id } ` ) ;
173
- dispatch ( {
174
- type : ActionTypes . NEW_PROJECT ,
175
- project : response . data ,
176
- owner : response . data . user ,
177
- files : response . data . files
178
- } ) ;
228
+ dispatch ( endSavingProject ( ) ) ;
179
229
dispatch ( setUnsavedChanges ( false ) ) ;
230
+ browserHistory . push ( `/${ response . data . user . username } /sketches/${ response . data . id } ` ) ;
231
+ const { hasChanges, synchedProject } = getSynchedProject ( getState ( ) , response . data ) ;
232
+ if ( hasChanges ) {
233
+ dispatch ( setUnsavedChanges ( true ) ) ;
234
+ }
235
+ dispatch ( setNewProject ( synchedProject ) ) ;
180
236
} )
181
- . catch ( response => dispatch ( {
182
- type : ActionTypes . PROJECT_SAVE_FAIL ,
183
- error : response . data
184
- } ) ) ;
237
+ . catch ( ( response ) => {
238
+ dispatch ( endSavingProject ( ) ) ;
239
+ dispatch ( projectSaveFail ( response . data ) ) ;
240
+ } ) ;
185
241
} ;
186
242
}
187
243
@@ -251,12 +307,7 @@ export function cloneProject() {
251
307
axios . post ( `${ ROOT_URL } /projects` , formParams , { withCredentials : true } )
252
308
. then ( ( response ) => {
253
309
browserHistory . push ( `/${ response . data . user . username } /sketches/${ response . data . id } ` ) ;
254
- dispatch ( {
255
- type : ActionTypes . NEW_PROJECT ,
256
- project : response . data ,
257
- owner : response . data . user ,
258
- files : response . data . files
259
- } ) ;
310
+ dispatch ( setNewProject ( response . data ) ) ;
260
311
} )
261
312
. catch ( response => dispatch ( {
262
313
type : ActionTypes . PROJECT_SAVE_FAIL ,
@@ -277,3 +328,10 @@ export function hideEditProjectName() {
277
328
type : ActionTypes . HIDE_EDIT_PROJECT_NAME
278
329
} ;
279
330
}
331
+
332
+ export function setProjectSavedTime ( updatedAt ) {
333
+ return {
334
+ type : ActionTypes . SET_PROJECT_SAVED_TIME ,
335
+ value : updatedAt
336
+ } ;
337
+ }
0 commit comments