1
- import React , { useEffect , useState } from 'react' ;
1
+ import React , { useEffect , useMemo , useState } from 'react' ;
2
2
import cx from 'classnames' ;
3
3
4
4
import ModalBodySNCF from 'common/BootstrapSNCF/ModalSNCF/ModalBodySNCF' ;
@@ -39,6 +39,25 @@ import { Point } from './types';
39
39
*
40
40
*/
41
41
42
+ enum IMPORT_STATUS {
43
+ READY = 'ready' ,
44
+ COMPLETING_POINTS = 'completing-points' ,
45
+ ALL_POINTS_COMPLETED = 'all-points-completed' ,
46
+ MISSING_ROLLING_STOCK = 'missing-rolling-stock' ,
47
+ PATHFINDINGS_RUNNING = 'pathfindings-running' ,
48
+ PATHFINDINGS_COMPLETED = 'pathfindings-completed' ,
49
+ PATHFINDINGS_FAILED = 'pathfindings-failed' ,
50
+ CREATING_TRAINS = 'creating-trains' ,
51
+ CREATING_TRAINS_COMPLETED = 'creating-trains-completed' ,
52
+ CREATING_TRAINS_FAILED = 'creating-trains-failed' ,
53
+ }
54
+
55
+ const IMPORT_STATUS_ERROR = [
56
+ IMPORT_STATUS . MISSING_ROLLING_STOCK ,
57
+ IMPORT_STATUS . PATHFINDINGS_FAILED ,
58
+ IMPORT_STATUS . CREATING_TRAINS_FAILED ,
59
+ ] ;
60
+
42
61
interface ImportTrainScheduleModalProps {
43
62
infraId : number ;
44
63
rollingStocks : LightRollingStock [ ] ;
@@ -72,20 +91,51 @@ const ImportTrainScheduleModal = ({
72
91
{ trainNumber : string ; pathString : string } [ ]
73
92
> ( [ ] ) ;
74
93
75
- const [ importStatus , setImportStatus ] = useState ( < span > { t ( 'status.ready' ) } </ span > ) ;
76
-
77
94
const [ viewport , setViewport ] = useState ( initialViewport ) ;
78
95
const [ status , setStatus ] = useState ( initialStatus ) ;
79
96
97
+ const [ importStatus , setImportStatus ] = useState < IMPORT_STATUS > ( IMPORT_STATUS . READY ) ;
98
+ const [ message , setMessage ] = useState ( '' ) ;
99
+
100
+ const updateImportStatus = ( newStatus : IMPORT_STATUS , newMessage = '' ) => {
101
+ if ( newStatus !== importStatus ) setImportStatus ( newStatus ) ;
102
+ if ( newMessage !== '' ) {
103
+ setMessage ( newMessage ) ;
104
+ } else {
105
+ switch ( newStatus ) {
106
+ case IMPORT_STATUS . MISSING_ROLLING_STOCK :
107
+ setMessage (
108
+ [ t ( 'status.noImportationPossible' ) , t ( 'status.missingRollingStock' ) ] . join ( '\n' )
109
+ ) ;
110
+ break ;
111
+ case IMPORT_STATUS . ALL_POINTS_COMPLETED :
112
+ setMessage ( t ( 'status.uicComplete' ) ) ;
113
+ break ;
114
+ case IMPORT_STATUS . PATHFINDINGS_COMPLETED :
115
+ setMessage ( t ( 'status.pathComplete' ) ) ;
116
+ break ;
117
+ case IMPORT_STATUS . PATHFINDINGS_FAILED :
118
+ setMessage ( t ( 'status.pathsFailed' ) ) ;
119
+ break ;
120
+ case IMPORT_STATUS . CREATING_TRAINS_FAILED :
121
+ setMessage ( t ( 'status.calculatingTrainScheduleCompleteAllFailure' ) ) ;
122
+ break ;
123
+ default :
124
+ setMessage ( '' ) ;
125
+ }
126
+ }
127
+ } ;
128
+
129
+ const importStatusIsError = useMemo (
130
+ ( ) => IMPORT_STATUS_ERROR . includes ( importStatus ) ,
131
+ [ importStatus ]
132
+ ) ;
133
+
80
134
function testMissingInfos ( ) {
81
135
if ( ! rollingStockID ) {
82
- setImportStatus (
83
- < span className = "text-danger" >
84
- { [ t ( 'status.noImportationPossible' ) , t ( 'status.missingRollingStock' ) ] . join ( '\n' ) }
85
- </ span >
86
- ) ;
136
+ updateImportStatus ( IMPORT_STATUS . MISSING_ROLLING_STOCK ) ;
87
137
} else {
88
- setImportStatus ( t ( 'status.ready' ) ) ;
138
+ updateImportStatus ( IMPORT_STATUS . READY ) ;
89
139
}
90
140
}
91
141
@@ -112,15 +162,16 @@ const ImportTrainScheduleModal = ({
112
162
setUicNumberToComplete ( uicNumberToCompleteLocal ) ;
113
163
const pointToComplete = pointsDictionnary [ uic2complete [ uicNumberToCompleteLocal ] ] ;
114
164
getTrackSectionID ( pointToComplete . latitude , pointToComplete . longitude ) ;
115
- setImportStatus (
165
+ updateImportStatus (
166
+ IMPORT_STATUS . COMPLETING_POINTS ,
116
167
t ( 'status.complete' , {
117
168
uicNumber : uicNumberToCompleteLocal ,
118
169
uicTotalCount : uic2complete . length ,
119
170
uicName : pointToComplete . name ,
120
171
} )
121
172
) ;
122
173
} else {
123
- setImportStatus ( t ( 'status.uicComplete' ) ) ;
174
+ updateImportStatus ( IMPORT_STATUS . ALL_POINTS_COMPLETED ) ;
124
175
setUicNumberToComplete ( undefined ) ;
125
176
setStatus ( { ...status , uicComplete : true } ) ;
126
177
}
@@ -132,10 +183,10 @@ const ImportTrainScheduleModal = ({
132
183
133
184
function endGeneratePaths ( newTrainsWithPath : TrainScheduleWithPath [ ] ) {
134
185
if ( newTrainsWithPath . length > 0 ) {
135
- setImportStatus ( t ( 'status.pathComplete' ) ) ;
136
- } else setImportStatus ( < span className = "text-danger" > { t ( 'status.pathsFailed' ) } </ span > ) ;
186
+ updateImportStatus ( IMPORT_STATUS . PATHFINDINGS_COMPLETED ) ;
187
+ } else updateImportStatus ( IMPORT_STATUS . PATHFINDINGS_FAILED ) ;
137
188
setTrainsWithPath ( newTrainsWithPath ) ;
138
- setStatus ( { ...status , uicComplete : true , pathFindingDone : true } ) ;
189
+ setStatus ( { ...status , pathFindingDone : true } ) ;
139
190
}
140
191
141
192
/**
@@ -163,7 +214,8 @@ const ImportTrainScheduleModal = ({
163
214
autocomplete ,
164
215
pointsDictionnary
165
216
) ;
166
- setImportStatus (
217
+ updateImportStatus (
218
+ IMPORT_STATUS . PATHFINDINGS_RUNNING ,
167
219
t ( 'status.searchingPath' , {
168
220
pathFindingsDoneCount,
169
221
pathFindingsCount,
@@ -227,34 +279,33 @@ const ImportTrainScheduleModal = ({
227
279
228
280
async function generateTrainSchedules ( ) {
229
281
const payloads = generateTrainSchedulesPayload ( trainsWithPath , timetableId ) ;
230
- const trainsCount = payloads . length ;
231
- setImportStatus ( t ( 'status.calculatingTrainSchedule' ) ) ;
282
+ const trainsCount = payloads . reduce ( ( result , payload ) => result + payload . schedules . length , 0 ) ;
283
+ updateImportStatus ( IMPORT_STATUS . CREATING_TRAINS , t ( 'status.calculatingTrainSchedule' ) ) ;
232
284
const messages = [ ] ;
233
285
let successfulTrainsCount = 0 ;
234
- let idx = 0 ;
235
286
// eslint-disable-next-line no-restricted-syntax
236
287
for await ( const payload of payloads ) {
237
288
const success = await launchTrainSchedules ( payload ) ;
238
- const message = `${ t (
239
- ! success
289
+ if ( success ) {
290
+ successfulTrainsCount += payload . schedules . length ;
291
+ }
292
+ const msg = `${ t (
293
+ success
240
294
? 'status.calculatingTrainScheduleComplete'
241
295
: 'errorMessages.unableToCreateTrainSchedule' ,
242
296
{
243
297
pathId : payload . path ,
244
- trainIndex : idx ,
245
- trainsCount : payloads . length ,
298
+ createdTrainsCount : successfulTrainsCount ,
299
+ trainsCount,
246
300
}
247
301
) } `;
248
- messages . push ( message ) ;
249
- if ( success ) {
250
- successfulTrainsCount += 1 ;
251
- }
252
- setImportStatus ( < > { messages . join ( '\n' ) } </ > ) ;
253
- idx += 1 ;
302
+ messages . push ( msg ) ;
303
+ updateImportStatus ( IMPORT_STATUS . CREATING_TRAINS , messages . join ( '\n' ) ) ;
254
304
}
255
305
if ( successfulTrainsCount > 0 ) {
256
306
setStatus ( { ...status , trainSchedulesDone : true , success : true } ) ;
257
- setImportStatus (
307
+ updateImportStatus (
308
+ IMPORT_STATUS . CREATING_TRAINS_COMPLETED ,
258
309
t ( 'status.calculatingTrainScheduleCompleteAll' , {
259
310
count : successfulTrainsCount ,
260
311
successfulTrainsCount,
@@ -263,11 +314,7 @@ const ImportTrainScheduleModal = ({
263
314
) ;
264
315
} else {
265
316
setStatus ( { ...status , trainSchedulesDone : true } ) ;
266
- setImportStatus (
267
- < span className = "text-danger" >
268
- { t ( 'status.calculatingTrainScheduleCompleteAllFailure' ) }
269
- </ span >
270
- ) ;
317
+ updateImportStatus ( IMPORT_STATUS . CREATING_TRAINS_FAILED ) ;
271
318
}
272
319
}
273
320
@@ -304,19 +351,27 @@ const ImportTrainScheduleModal = ({
304
351
{ ! infraId || ! timetableId || ! rollingStockID ? null : (
305
352
< >
306
353
< button
307
- className = { `btn btn-sm btn-block d-flex justify-content-between ${
308
- status . uicComplete ? 'btn-outline-success' : 'btn-primary'
309
- } `}
354
+ className = { cx ( 'btn' , 'btn-sm' , 'btn-block' , 'd-flex' , 'justify-content-between' , {
355
+ 'btn-primary' : ! status . uicComplete && ! status . pathFindingDone ,
356
+ 'btn-outline-success' : status . uicComplete ,
357
+ 'btn-outline-secondary' : ! status . uicComplete && status . pathFindingDone ,
358
+ } ) }
310
359
type = "button"
311
360
onClick = { ( ) => completePaths ( true ) }
312
361
>
313
362
< span > 1 — { t ( 'completeTrackSectionID' ) } </ span >
314
363
< span > { Object . keys ( pointsDictionnary ) . length } </ span >
315
364
</ button >
316
365
< button
317
- className = { `btn btn-sm btn-block d-flex justify-content-between ${
318
- status . pathFindingDone ? 'btn-outline-success' : 'btn-primary'
319
- } `}
366
+ className = { cx ( 'btn' , 'btn-sm' , 'btn-block' , 'd-flex' , 'justify-content-between' , {
367
+ 'btn-primary' : ! status . pathFindingDone ,
368
+ 'btn-outline-danger' :
369
+ status . uicComplete && importStatus === IMPORT_STATUS . PATHFINDINGS_FAILED ,
370
+ 'btn-outline-success' :
371
+ status . uicComplete &&
372
+ status . pathFindingDone &&
373
+ importStatus !== IMPORT_STATUS . PATHFINDINGS_FAILED ,
374
+ } ) }
320
375
disabled = { ! status . uicComplete }
321
376
type = "button"
322
377
onClick = { ( ) => generatePaths ( ) }
@@ -327,25 +382,33 @@ const ImportTrainScheduleModal = ({
327
382
< div className = "my-1 text-center" > { t ( 'or' ) } </ div >
328
383
< button
329
384
className = { cx (
330
- 'btn btn-sm btn-block d-flex justify-content-between text-wrap text-left' ,
331
- ! status . pathFindingDone && 'btn-primary' ,
332
- status . pathFindingDone && trainsWithPath . length && 'btn-outline-success' ,
333
- status . pathFindingDone && ! trainsWithPath . length && 'btn-outline-danger'
385
+ 'btn' ,
386
+ 'btn-sm' ,
387
+ 'btn-block' ,
388
+ 'd-flex' ,
389
+ 'justify-content-between' ,
390
+ 'text-wrap' ,
391
+ 'text-left' ,
392
+ {
393
+ 'btn-primary' : ! status . pathFindingDone ,
394
+ 'btn-outline-success' : status . pathFindingDone && ! status . uicComplete ,
395
+ 'btn-outline-danger' : status . pathFindingDone && ! trainsWithPath . length ,
396
+ }
334
397
) }
335
398
type = "button"
399
+ disabled = { status . pathFindingDone && status . uicComplete }
336
400
onClick = { generateAutocompletePaths }
337
401
>
338
402
< span > 1/2 — { t ( 'generatePathsAuto' ) } </ span >
339
403
< span > { pathsDictionnary . length } </ span >
340
404
</ button >
341
405
< Spacer height = { 50 } />
342
406
< button
343
- className = { cx (
344
- 'btn btn-sm btn-block d-flex justify-content-between' ,
345
- ! status . trainSchedulesDone && 'btn-primary' ,
346
- status . trainSchedulesDone && ! status . success && 'btn-outline-danger' ,
347
- status . trainSchedulesDone && status . success && 'btn-outline-success'
348
- ) }
407
+ className = { cx ( 'btn' , 'btn-sm' , 'btn-block' , 'd-flex' , 'justify-content-between' , {
408
+ 'btn-primary' : ! status . trainSchedulesDone ,
409
+ 'btn-outline-danger' : importStatus === IMPORT_STATUS . CREATING_TRAINS_FAILED ,
410
+ 'btn-outline-success' : importStatus === IMPORT_STATUS . CREATING_TRAINS_COMPLETED ,
411
+ } ) }
349
412
disabled = { ! status . pathFindingDone || trainsWithPath . length === 0 }
350
413
type = "button"
351
414
onClick = { generateTrainSchedules }
@@ -358,7 +421,7 @@ const ImportTrainScheduleModal = ({
358
421
</ >
359
422
) }
360
423
361
- < pre > { importStatus } </ pre >
424
+ < p className = { cx ( { 'text-danger' : importStatusIsError } ) } > { message } </ p >
362
425
363
426
{ uicNumberToComplete !== undefined && (
364
427
< div className = "automated-map" >
0 commit comments