1+ /* eslint-disable max-statements */
12import React , { useState , useCallback , useEffect } from 'react'
23
34import {
@@ -11,7 +12,9 @@ import {
1112 Tooltip ,
1213 IconButton ,
1314 Button ,
14- Autocomplete
15+ Autocomplete ,
16+ CircularProgress ,
17+ Alert
1518} from '@mui/material'
1619
1720import InfoIcon from '@mui/icons-material/Info'
@@ -28,24 +31,48 @@ import {
2831
2932import { Cohort } from 'types'
3033import { TableSetting , TableInfo } from 'types/export'
31- import { useSearchParams } from 'react-router-dom'
34+ import { useNavigate , useSearchParams } from 'react-router-dom'
3235
3336import useStyles from '../../styles'
3437
38+ export enum Error {
39+ ERROR_MOTIF ,
40+ ERROR_CONDITION ,
41+ ERROR_TABLE ,
42+ ERROR_TABLE_LIMIT ,
43+ ERROR_FETCH ,
44+ NO_ERROR
45+ }
46+
47+ type ErrorTables = [
48+ {
49+ tableName : string
50+ error : Error
51+ }
52+ ]
53+
3554const tableSettingsInitialState : TableSetting [ ] = [
3655 {
3756 tableName : 'person' ,
3857 isChecked : true ,
3958 columns : null ,
4059 fhirFilter : null ,
4160 respectTableRelationships : true ,
42- pivotMerge : null
61+ pivotMerge : false
62+ }
63+ ]
64+
65+ const errorTablesInitialState : ErrorTables = [
66+ {
67+ tableName : 'person' ,
68+ error : Error . NO_ERROR
4369 }
4470]
4571
4672const ExportForm : React . FC = ( ) => {
4773 const { classes } = useStyles ( )
48- const [ error , setError ] = useState < any > ( '' )
74+ const [ error , setError ] = useState < Error | null > ( null )
75+ const [ errorTables , setErrorTables ] = useState < ErrorTables > ( errorTablesInitialState )
4976 const [ oneFile , setOneFile ] = useState < boolean > ( false )
5077 const [ exportTypeFile , setExportTypeFile ] = useState < 'csv' | 'xlsx' > ( 'csv' )
5178 const [ tablesSettings , setTablesSettings ] = useState < TableSetting [ ] > ( tableSettingsInitialState )
@@ -55,9 +82,13 @@ const ExportForm: React.FC = () => {
5582 const checkedTables = tablesSettings . filter ( ( tableSetting ) => tableSetting . isChecked )
5683 const [ compatibilitiesTables , setCompatibilitiesTables ] = useState < string [ ] | null > ( null )
5784 const [ conditions , setConditions ] = useState < boolean > ( false )
58- const [ motivation , setMotivation ] = useState < string > ( '' )
85+ const [ motivation , setMotivation ] = useState < string | null > ( null )
5986 const [ searchParams , setSearchParams ] = useSearchParams ( )
6087 const cohortID = searchParams . get ( 'groupId' )
88+ const [ loading , setLoading ] = useState < boolean > ( false )
89+ const navigate = useNavigate ( )
90+
91+ const limitError = errorTables . some ( ( errorTable ) => errorTable . error === Error . ERROR_TABLE_LIMIT )
6192
6293 const _fetchExportableCohorts = useCallback ( async ( ) => {
6394 try {
@@ -70,8 +101,10 @@ const ExportForm: React.FC = () => {
70101
71102 const _fetchExportTablesInfo = useCallback ( async ( ) => {
72103 try {
104+ setLoading ( true )
73105 const response = await fetchExportTablesInfo ( )
74106 setExportTableList ( response )
107+ setLoading ( false )
75108 } catch ( error ) {
76109 return [ ]
77110 }
@@ -129,6 +162,20 @@ const ExportForm: React.FC = () => {
129162 setTablesSettings ( newTableSettings )
130163 }
131164
165+ const onChangeError = ( tableName : string , errorValue : Error ) => {
166+ const newErrorTableSettings : any = tablesSettings . map ( ( tableSetting ) => {
167+ if ( tableSetting . tableName === tableName ) {
168+ return {
169+ ...tableSetting ,
170+ error : errorValue
171+ }
172+ } else {
173+ return tableSetting
174+ }
175+ } )
176+ setErrorTables ( newErrorTableSettings )
177+ }
178+
132179 const resetSelectedTables = ( ) => {
133180 const newSelectedTables = tablesSettings . map ( ( tableSetting ) => ( {
134181 ...tableSetting ,
@@ -150,11 +197,27 @@ const ExportForm: React.FC = () => {
150197
151198 postExportCohort ( {
152199 cohortId : exportCohort ?? { uuid : '' } ,
153- motivation : motivation ,
200+ motivation : motivation ?? '' ,
154201 group_tables : oneFile ,
155202 outputFormat : exportTypeFile ,
156203 tables : tableToExport
157204 } )
205+ navigate ( `/home` )
206+ }
207+
208+ const handleChangeMotivation = ( e : React . ChangeEvent < HTMLInputElement | HTMLTextAreaElement > ) => {
209+ if ( e . target . value . length < 10 ) {
210+ setMotivation ( e . target . value )
211+ setError ( Error . ERROR_MOTIF )
212+ }
213+ if ( e . target . value . length >= 10 ) {
214+ setMotivation ( e . target . value )
215+ setError ( null )
216+ }
217+ if ( e . target . value . length === 0 ) {
218+ setMotivation ( null )
219+ setError ( null )
220+ }
158221 }
159222
160223 return (
@@ -174,14 +237,13 @@ const ExportForm: React.FC = () => {
174237 maxRows = { 5 }
175238 style = { { marginTop : '20px' , backgroundColor : 'white' } }
176239 value = { motivation }
177- FormHelperTextProps = { { className : classes . helperText } }
178240 label = "Motif de l'export"
179241 variant = "outlined"
180- onChange = { ( e ) => setMotivation ( e . target . value ) }
181- error = { error }
242+ onChange = { ( e ) => handleChangeMotivation ( e ) }
243+ error = { error === Error . ERROR_MOTIF }
182244 />
183245
184- < Typography style = { error ? { color : 'red' } : { color : 'black' } } >
246+ < Typography style = { error === Error . ERROR_MOTIF ? { color : 'red' } : { color : 'black' } } >
185247 Le motif doit comporter au moins 10 caractères
186248 </ Typography >
187249
@@ -294,34 +356,28 @@ const ExportForm: React.FC = () => {
294356 ) }
295357 </ Grid >
296358
297- < Grid >
298- { exportTableList ?. map ( ( exportTable , index : number ) => (
299- < div
300- style = { {
301- padding : '16px 16px 16px 16px' ,
302- backgroundColor : 'white' ,
303- marginBottom : '10px' ,
304- borderColor : 'grey' ,
305- borderRadius : 9 ,
306- border : 'solid' ,
307- borderWidth : 1.5
308- } }
309- key = { exportTable . name + index }
310- >
359+ { loading ? (
360+ < Grid container className = { classes . exportTableGrid } justifyContent = { 'center' } >
361+ < CircularProgress />
362+ </ Grid >
363+ ) : (
364+ < >
365+ { exportTableList ?. map ( ( exportTable , index : number ) => (
311366 < ExportTable
367+ key = { exportTable . name + index }
312368 exportCohort = { exportCohort }
313369 exportTable = { exportTable }
314370 exportTableSettings = { tablesSettings }
315- setError = { setError }
371+ setError = { onChangeError }
316372 addNewTableSetting = { addNewTableSetting }
317373 onChangeTableSettings = { onChangeTableSettings }
318374 compatibilitiesTables = { compatibilitiesTables }
319375 exportTypeFile = { exportTypeFile }
320376 oneFile = { oneFile }
321377 />
322- </ div >
323- ) ) }
324- </ Grid >
378+ ) ) }
379+ </ >
380+ ) }
325381
326382 < Grid container gap = "12px" pb = "10px" >
327383 < Typography className = { classes . dialogHeader } variant = "h5" >
@@ -341,39 +397,37 @@ const ExportForm: React.FC = () => {
341397 </ Typography >
342398
343399 < Typography variant = "caption" className = { classes . conditionItem } >
344- A stocker temporairement les données extraites sur un répertoire dont l’accès est techniquement restreint
400+ À stocker temporairement les données extraites sur un répertoire dont l’accès est techniquement restreint
345401 aux personnes dûment habilitées et authentifiées, présentes dans les locaux du responsable de la
346402 recherche.
347403 </ Typography >
348404
349405 < Typography variant = "caption" className = { classes . conditionItem } >
350- A ne pas utiliser du matériel ou des supports de stockage n’appartenant pas à l’AP-HP, à ne pas sortir les
406+ À ne pas utiliser du matériel ou des supports de stockage n’appartenant pas à l’AP-HP, à ne pas sortir les
351407 données des locaux de l’AP-HP ou sur un support amovible emporté hors AP-HP.
352408 </ Typography >
353409 < Typography variant = "caption" className = { classes . conditionItem } >
354- A procéder à la destruction de toutes données exportées, dès qu’il n’y a plus nécessité d’en disposer dans
410+ À procéder à la destruction de toutes données exportées, dès qu’il n’y a plus nécessité d’en disposer dans
355411 le cadre de la recherche dans le périmètre concerné.
356412 </ Typography >
357413
358414 < Typography variant = "caption" className = { classes . conditionItem } >
359- A ne pas communiquer les données à des tiers non autorisés
415+ À ne pas communiquer les données à des tiers non autorisés
360416 </ Typography >
361417
362418 < Typography variant = "caption" className = { classes . conditionItem } >
363- A informer les chefs de services des UF de Responsabilité où ont été collectées les données exportées
419+ À informer les chefs de services des UF de Responsabilité où ont été collectées les données exportées
364420 </ Typography >
365421
366422 < Typography variant = "caption" className = { classes . conditionItem } >
367- A ne pas croiser les données avec tout autre jeu de données, sans autorisation auprès de la CNIL
423+ À ne pas croiser les données avec tout autre jeu de données, sans autorisation auprès de la CNIL
368424 </ Typography >
369425 </ Grid >
370426
371427 < FormControlLabel
372- className = { classes . selectAgreeConditions }
373428 control = {
374429 < Checkbox
375430 color = "secondary"
376- className = { classes . agreeCheckbox }
377431 name = "conditions"
378432 checked = { conditions }
379433 onChange = { ( ) => setConditions ( ! conditions ) }
@@ -386,11 +440,31 @@ const ExportForm: React.FC = () => {
386440 </ Typography >
387441 }
388442 />
389- < Button disabled = { conditions === false } onClick = { handleSubmitPayload } >
443+ < Button
444+ disabled = { conditions === false || motivation === null || error === Error . ERROR_MOTIF || limitError }
445+ onClick = { handleSubmitPayload }
446+ >
390447 Confirmer
391448 </ Button >
392449 </ Grid >
393450 </ Grid >
451+ < Grid container item mb = "12px" justifyContent = { 'flex-end' } >
452+ { error === Error . ERROR_MOTIF && (
453+ < Alert severity = "error" >
454+ Merci d'indiquer le motif de votre demande d'export, ce motif doit contenir au moins 10 caractères
455+ </ Alert >
456+ ) }
457+
458+ { error === Error . ERROR_CONDITION && (
459+ < Alert severity = "error" > Merci d'accepter toutes les conditions de l'Entrepôt de données de santé</ Alert >
460+ ) }
461+ { error === Error . ERROR_TABLE && (
462+ < Alert severity = "error" > Merci d'indiquer les tables que vous voulez exporter</ Alert >
463+ ) }
464+ { limitError && (
465+ < Alert severity = "error" > Merci d'indiquer des tables qui respectent la limite de lignes autorisées</ Alert >
466+ ) }
467+ </ Grid >
394468 </ Grid >
395469 )
396470}
0 commit comments