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' ;
@@ -41,6 +41,25 @@ import { Point } from './types';
41
41
*
42
42
*/
43
43
44
+ enum IMPORT_STATUS {
45
+ READY = 'ready' ,
46
+ COMPLETING_POINTS = 'completing-points' ,
47
+ ALL_POINTS_COMPLETED = 'all-points-completed' ,
48
+ MISSING_ROLLING_STOCK = 'missing-rolling-stock' ,
49
+ PATHFINDINGS_RUNNING = 'pathfindings-running' ,
50
+ PATHFINDINGS_COMPLETED = 'pathfindings-completed' ,
51
+ PATHFINDINGS_FAILED = 'pathfindings-failed' ,
52
+ CREATING_TRAINS = 'creating-trains' ,
53
+ CREATING_TRAINS_COMPLETED = 'creating-trains-completed' ,
54
+ CREATING_TRAINS_FAILED = 'creating-trains-failed' ,
55
+ }
56
+
57
+ const IMPORT_STATUS_ERROR = [
58
+ IMPORT_STATUS . MISSING_ROLLING_STOCK ,
59
+ IMPORT_STATUS . PATHFINDINGS_FAILED ,
60
+ IMPORT_STATUS . CREATING_TRAINS_FAILED ,
61
+ ] ;
62
+
44
63
interface ImportTrainScheduleModalProps {
45
64
infraId : number ;
46
65
rollingStocks : LightRollingStock [ ] ;
@@ -77,20 +96,51 @@ const ImportTrainScheduleModal = ({
77
96
{ trainNumber : string ; pathString : string } [ ]
78
97
> ( [ ] ) ;
79
98
80
- const [ importStatus , setImportStatus ] = useState ( < span > { t ( 'status.ready' ) } </ span > ) ;
81
-
82
99
const [ viewport , setViewport ] = useState ( initialViewport ) ;
83
100
const [ status , setStatus ] = useState ( initialStatus ) ;
84
101
102
+ const [ importStatus , setImportStatus ] = useState < IMPORT_STATUS > ( IMPORT_STATUS . READY ) ;
103
+ const [ message , setMessage ] = useState ( '' ) ;
104
+
105
+ const updateImportStatus = ( newStatus : IMPORT_STATUS , newMessage = '' ) => {
106
+ if ( newStatus !== importStatus ) setImportStatus ( newStatus ) ;
107
+ if ( newMessage !== '' ) {
108
+ setMessage ( newMessage ) ;
109
+ } else {
110
+ switch ( newStatus ) {
111
+ case IMPORT_STATUS . MISSING_ROLLING_STOCK :
112
+ setMessage (
113
+ [ t ( 'status.noImportationPossible' ) , t ( 'status.missingRollingStock' ) ] . join ( '\n' )
114
+ ) ;
115
+ break ;
116
+ case IMPORT_STATUS . ALL_POINTS_COMPLETED :
117
+ setMessage ( t ( 'status.uicComplete' ) ) ;
118
+ break ;
119
+ case IMPORT_STATUS . PATHFINDINGS_COMPLETED :
120
+ setMessage ( t ( 'status.pathComplete' ) ) ;
121
+ break ;
122
+ case IMPORT_STATUS . PATHFINDINGS_FAILED :
123
+ setMessage ( t ( 'status.pathsFailed' ) ) ;
124
+ break ;
125
+ case IMPORT_STATUS . CREATING_TRAINS_FAILED :
126
+ setMessage ( t ( 'status.calculatingTrainScheduleCompleteAllFailure' ) ) ;
127
+ break ;
128
+ default :
129
+ setMessage ( '' ) ;
130
+ }
131
+ }
132
+ } ;
133
+
134
+ const importStatusIsError = useMemo (
135
+ ( ) => IMPORT_STATUS_ERROR . includes ( importStatus ) ,
136
+ [ importStatus ]
137
+ ) ;
138
+
85
139
function testMissingInfos ( ) {
86
140
if ( ! rollingStockID ) {
87
- setImportStatus (
88
- < span className = "text-danger" >
89
- { [ t ( 'status.noImportationPossible' ) , t ( 'status.missingRollingStock' ) ] . join ( '\n' ) }
90
- </ span >
91
- ) ;
141
+ updateImportStatus ( IMPORT_STATUS . MISSING_ROLLING_STOCK ) ;
92
142
} else {
93
- setImportStatus ( t ( 'status.ready' ) ) ;
143
+ updateImportStatus ( IMPORT_STATUS . READY ) ;
94
144
}
95
145
}
96
146
@@ -117,15 +167,16 @@ const ImportTrainScheduleModal = ({
117
167
setUicNumberToComplete ( uicNumberToCompleteLocal ) ;
118
168
const pointToComplete = pointsDictionnary [ uic2complete [ uicNumberToCompleteLocal ] ] ;
119
169
getTrackSectionID ( pointToComplete . latitude , pointToComplete . longitude ) ;
120
- setImportStatus (
170
+ updateImportStatus (
171
+ IMPORT_STATUS . COMPLETING_POINTS ,
121
172
t ( 'status.complete' , {
122
173
uicNumber : uicNumberToCompleteLocal ,
123
174
uicTotalCount : uic2complete . length ,
124
175
uicName : pointToComplete . name ,
125
176
} )
126
177
) ;
127
178
} else {
128
- setImportStatus ( t ( 'status.uicComplete' ) ) ;
179
+ updateImportStatus ( IMPORT_STATUS . ALL_POINTS_COMPLETED ) ;
129
180
setUicNumberToComplete ( undefined ) ;
130
181
setStatus ( { ...status , uicComplete : true } ) ;
131
182
}
@@ -137,10 +188,10 @@ const ImportTrainScheduleModal = ({
137
188
138
189
function endGeneratePaths ( newTrainsWithPath : TrainScheduleWithPath [ ] ) {
139
190
if ( newTrainsWithPath . length > 0 ) {
140
- setImportStatus ( t ( 'status.pathComplete' ) ) ;
141
- } else setImportStatus ( < span className = "text-danger" > { t ( 'status.pathsFailed' ) } </ span > ) ;
191
+ updateImportStatus ( IMPORT_STATUS . PATHFINDINGS_COMPLETED ) ;
192
+ } else updateImportStatus ( IMPORT_STATUS . PATHFINDINGS_FAILED ) ;
142
193
setTrainsWithPath ( newTrainsWithPath ) ;
143
- setStatus ( { ...status , uicComplete : true , pathFindingDone : true } ) ;
194
+ setStatus ( { ...status , pathFindingDone : true } ) ;
144
195
}
145
196
146
197
/**
@@ -168,7 +219,8 @@ const ImportTrainScheduleModal = ({
168
219
autocomplete ,
169
220
pointsDictionnary
170
221
) ;
171
- setImportStatus (
222
+ updateImportStatus (
223
+ IMPORT_STATUS . PATHFINDINGS_RUNNING ,
172
224
t ( 'status.searchingPath' , {
173
225
pathFindingsDoneCount,
174
226
pathFindingsCount,
@@ -242,34 +294,33 @@ const ImportTrainScheduleModal = ({
242
294
243
295
async function generateTrainSchedules ( ) {
244
296
const payloads = generateTrainSchedulesPayload ( trainsWithPath , timetableId ) ;
245
- const trainsCount = payloads . length ;
246
- setImportStatus ( t ( 'status.calculatingTrainSchedule' ) ) ;
297
+ const trainsCount = payloads . reduce ( ( result , payload ) => result + payload . schedules . length , 0 ) ;
298
+ updateImportStatus ( IMPORT_STATUS . CREATING_TRAINS , t ( 'status.calculatingTrainSchedule' ) ) ;
247
299
const messages = [ ] ;
248
300
let successfulTrainsCount = 0 ;
249
- let idx = 0 ;
250
301
// eslint-disable-next-line no-restricted-syntax
251
302
for await ( const payload of payloads ) {
252
303
const success = await launchTrainSchedules ( payload ) ;
253
- const message = `${ t (
254
- ! success
304
+ if ( success ) {
305
+ successfulTrainsCount += payload . schedules . length ;
306
+ }
307
+ const msg = `${ t (
308
+ success
255
309
? 'status.calculatingTrainScheduleComplete'
256
310
: 'errorMessages.unableToCreateTrainSchedule' ,
257
311
{
258
312
pathId : payload . path ,
259
- trainIndex : idx ,
260
- trainsCount : payloads . length ,
313
+ createdTrainsCount : successfulTrainsCount ,
314
+ trainsCount,
261
315
}
262
316
) } `;
263
- messages . push ( message ) ;
264
- if ( success ) {
265
- successfulTrainsCount += 1 ;
266
- }
267
- setImportStatus ( < > { messages . join ( '\n' ) } </ > ) ;
268
- idx += 1 ;
317
+ messages . push ( msg ) ;
318
+ updateImportStatus ( IMPORT_STATUS . CREATING_TRAINS , messages . join ( '\n' ) ) ;
269
319
}
270
320
if ( successfulTrainsCount > 0 ) {
271
321
setStatus ( { ...status , trainSchedulesDone : true , success : true } ) ;
272
- setImportStatus (
322
+ updateImportStatus (
323
+ IMPORT_STATUS . CREATING_TRAINS_COMPLETED ,
273
324
t ( 'status.calculatingTrainScheduleCompleteAll' , {
274
325
count : successfulTrainsCount ,
275
326
successfulTrainsCount,
@@ -278,11 +329,7 @@ const ImportTrainScheduleModal = ({
278
329
) ;
279
330
} else {
280
331
setStatus ( { ...status , trainSchedulesDone : true } ) ;
281
- setImportStatus (
282
- < span className = "text-danger" >
283
- { t ( 'status.calculatingTrainScheduleCompleteAllFailure' ) }
284
- </ span >
285
- ) ;
332
+ updateImportStatus ( IMPORT_STATUS . CREATING_TRAINS_FAILED ) ;
286
333
}
287
334
}
288
335
@@ -319,19 +366,27 @@ const ImportTrainScheduleModal = ({
319
366
{ ! infraId || ! timetableId || ! rollingStockID ? null : (
320
367
< >
321
368
< button
322
- className = { `btn btn-sm btn-block d-flex justify-content-between ${
323
- status . uicComplete ? 'btn-outline-success' : 'btn-primary'
324
- } `}
369
+ className = { cx ( 'btn btn-sm btn-block d-flex justify-content-between' , {
370
+ 'btn-primary' : ! status . uicComplete && ! status . pathFindingDone ,
371
+ 'btn-outline-success' : status . uicComplete ,
372
+ 'btn-outline-secondary' : ! status . uicComplete && status . pathFindingDone ,
373
+ } ) }
325
374
type = "button"
326
375
onClick = { ( ) => completePaths ( true ) }
327
376
>
328
377
< span > 1 — { t ( 'completeTrackSectionID' ) } </ span >
329
378
< span > { Object . keys ( pointsDictionnary ) . length } </ span >
330
379
</ button >
331
380
< button
332
- className = { `btn btn-sm btn-block d-flex justify-content-between ${
333
- status . pathFindingDone ? 'btn-outline-success' : 'btn-primary'
334
- } `}
381
+ className = { cx ( 'btn btn-sm btn-block d-flex justify-content-between' , {
382
+ 'btn-primary' : ! status . pathFindingDone ,
383
+ 'btn-outline-danger' :
384
+ status . uicComplete && importStatus === IMPORT_STATUS . PATHFINDINGS_FAILED ,
385
+ 'btn-outline-success' :
386
+ status . uicComplete &&
387
+ status . pathFindingDone &&
388
+ importStatus !== IMPORT_STATUS . PATHFINDINGS_FAILED ,
389
+ } ) }
335
390
disabled = { ! status . uicComplete }
336
391
type = "button"
337
392
onClick = { ( ) => generatePaths ( ) }
@@ -343,24 +398,26 @@ const ImportTrainScheduleModal = ({
343
398
< button
344
399
className = { cx (
345
400
'btn btn-sm btn-block d-flex justify-content-between text-wrap text-left' ,
346
- ! status . pathFindingDone && 'btn-primary' ,
347
- status . pathFindingDone && trainsWithPath . length && 'btn-outline-success' ,
348
- status . pathFindingDone && ! trainsWithPath . length && 'btn-outline-danger'
401
+ {
402
+ 'btn-primary' : ! status . pathFindingDone ,
403
+ 'btn-outline-success' : status . pathFindingDone && ! status . uicComplete ,
404
+ 'btn-outline-danger' : status . pathFindingDone && ! trainsWithPath . length ,
405
+ }
349
406
) }
350
407
type = "button"
408
+ disabled = { status . pathFindingDone && status . uicComplete }
351
409
onClick = { generateAutocompletePaths }
352
410
>
353
411
< span > 1/2 — { t ( 'generatePathsAuto' ) } </ span >
354
412
< span > { pathsDictionnary . length } </ span >
355
413
</ button >
356
414
< Spacer height = { 50 } />
357
415
< button
358
- className = { cx (
359
- 'btn btn-sm btn-block d-flex justify-content-between' ,
360
- ! status . trainSchedulesDone && 'btn-primary' ,
361
- status . trainSchedulesDone && ! status . success && 'btn-outline-danger' ,
362
- status . trainSchedulesDone && status . success && 'btn-outline-success'
363
- ) }
416
+ className = { cx ( 'btn btn-sm btn-block d-flex justify-content-between' , {
417
+ 'btn-primary' : ! status . trainSchedulesDone ,
418
+ 'btn-outline-danger' : importStatus === IMPORT_STATUS . CREATING_TRAINS_FAILED ,
419
+ 'btn-outline-success' : importStatus === IMPORT_STATUS . CREATING_TRAINS_COMPLETED ,
420
+ } ) }
364
421
disabled = { ! status . pathFindingDone || trainsWithPath . length === 0 }
365
422
type = "button"
366
423
onClick = { generateTrainSchedules }
@@ -373,7 +430,7 @@ const ImportTrainScheduleModal = ({
373
430
</ >
374
431
) }
375
432
376
- < pre > { importStatus } </ pre >
433
+ < p className = { cx ( importStatusIsError && 'text-danger' ) } > { message } </ p >
377
434
378
435
{ uicNumberToComplete !== undefined && (
379
436
< div className = "automated-map" >
0 commit comments