1- // @ts -nocheck
21import { useEffect , useMemo , useState } from 'react' ;
32import { usePapaParse } from 'react-papaparse' ;
43import { useDispatch , useSelector } from 'react-redux' ;
5- import { AppState } from '../store/initialState' ;
4+ import { AppState } from '../../../store/initialState' ;
5+ import { EventId } from '@wca/helpers' ;
66import {
77 Accordion ,
88 AccordionDetails ,
@@ -26,27 +26,73 @@ import { useBreadcrumbs } from '../../../providers/BreadcrumbsProvider';
2626import { partialUpdateWCIF } from '../../../store/actions' ;
2727import CSVPreview from './CSVPreview' ;
2828
29- const mapCSVFieldToData = ( necessaryFields ) => ( field ) => {
29+ // Define types for the CSV data
30+ interface CSVMeta {
31+ fields : string [ ] ;
32+ delimiter : string ;
33+ linebreak : string ;
34+ aborted : boolean ;
35+ truncated : boolean ;
36+ cursor : number ;
37+ }
38+
39+ interface CSVRow {
40+ email : string ;
41+ [ key : string ] : string ;
42+ }
43+
44+ interface CSVData {
45+ meta : CSVMeta ;
46+ data : CSVRow [ ] ;
47+ errors : any [ ] ;
48+ }
49+
50+ interface Assignment {
51+ registrantId : number ;
52+ eventId : EventId ;
53+ groupNumber : number ;
54+ activityCode : string ;
55+ assignmentCode : string ;
56+ roomId ?: number ;
57+ roundNumber ?: number ;
58+ }
59+
60+ interface MissingActivity {
61+ activityCode : string ;
62+ groupNumber : number ;
63+ eventId : EventId ;
64+ roundNumber : number ;
65+ roomId : number ;
66+ }
67+
68+ interface ValidationCheck {
69+ key : string ;
70+ passed : boolean ;
71+ message : string ;
72+ data ?: any ;
73+ }
74+
75+ const mapCSVFieldToData = ( necessaryFields : string [ ] ) => ( field : string ) : string | null => {
3076 if ( necessaryFields . indexOf ( field ) > - 1 ) {
3177 return field ;
3278 }
3379
3480 return null ;
3581} ;
3682
37- const ImportPage = ( props ?: any ) => {
83+ const ImportPage = ( ) => {
3884 const wcif = useSelector ( ( state : AppState ) => state . wcif ) ;
39- const eventIds = wcif . events . map ( ( e ) => e . id ) ;
85+ const eventIds = wcif ? .events . map ( ( e ) => e . id ) || [ ] ;
4086 const necessaryFields = [ 'email' , ...eventIds , ...eventIds . map ( ( e ) => `${ e } -staff` ) ] ;
4187 const dispatch = useDispatch ( ) ;
4288 const { setBreadcrumbs } = useBreadcrumbs ( ) ;
4389 const { readString } = usePapaParse ( ) ;
44- const [ file , setFile ] = useState ( ) ;
45- const [ CSVContents , setCSVContents ] = useState ( ) ;
46- const [ CSVColumnMap , setCSVColumnMap ] = useState ( ) ;
47- const [ competitorAssignments , setCompetitorAssignments ] = useState ( ) ;
48- const [ missingGroupActivities , setMissingGroupActivities ] = useState ( ) ;
49- const [ assignmentGenerationError , setAssignmentGenerationError ] = useState ( ) ;
90+ const [ file , setFile ] = useState < File | undefined > ( ) ;
91+ const [ CSVContents , setCSVContents ] = useState < CSVData | undefined > ( ) ;
92+ const [ CSVColumnMap , setCSVColumnMap ] = useState < Record < string , string > | undefined > ( ) ;
93+ const [ competitorAssignments , setCompetitorAssignments ] = useState < Assignment [ ] | undefined > ( ) ;
94+ const [ missingGroupActivities , setMissingGroupActivities ] = useState < MissingActivity [ ] | undefined > ( ) ;
95+ const [ assignmentGenerationError , setAssignmentGenerationError ] = useState < Error | null > ( ) ;
5096 const validateContents = useMemo ( ( ) => wcif && validate ( wcif ) , [ wcif ] ) ;
5197 const validation = useMemo (
5298 ( ) => validateContents && CSVContents && validateContents ( CSVContents ) ,
@@ -63,48 +109,56 @@ const ImportPage = (props?: any) => {
63109
64110 const fileReader = new FileReader ( ) ;
65111
66- const handleOnChange = ( e ) => {
67- setFile ( e . target . files [ 0 ] ) ;
112+ const handleOnChange = ( e : React . ChangeEvent < HTMLInputElement > ) => {
113+ if ( e . target . files && e . target . files [ 0 ] ) {
114+ setFile ( e . target . files [ 0 ] ) ;
115+ }
68116 } ;
69117
70- const handleOnSubmit = ( e ) => {
118+ const handleOnSubmit = ( e : React . FormEvent ) => {
71119 e . preventDefault ( ) ;
72120
73121 if ( file ) {
74122 fileReader . onload = function ( event ) {
75- const csvOutput = event . target . result ;
76- readString ( csvOutput , {
77- worker : false ,
78- header : true ,
79- skipEmptyLines : true ,
80- transformHeader : ( header ) => header . trim ( ) . toLowerCase ( ) ,
81- complete : ( results ) => {
82- const columnMap = { } ;
83- results . meta . fields . forEach ( ( field ) => {
84- const mappedField = mapCSVFieldToData ( necessaryFields ) ( field ) ;
85- if ( mappedField ) {
86- columnMap [ field ] = mappedField ;
123+ const csvOutput = event . target ?. result ;
124+ if ( typeof csvOutput === 'string' ) {
125+ readString ( csvOutput , {
126+ worker : false ,
127+ header : true ,
128+ skipEmptyLines : true ,
129+ transformHeader : ( header : string ) => header . trim ( ) . toLowerCase ( ) ,
130+ complete : ( results : any ) => {
131+ const columnMap : Record < string , string > = { } ;
132+ if ( results . meta . fields ) {
133+ results . meta . fields . forEach ( ( field : string ) => {
134+ const mappedField = mapCSVFieldToData ( necessaryFields ) ( field ) ;
135+ if ( mappedField ) {
136+ columnMap [ field ] = mappedField ;
137+ }
138+ } ) ;
87139 }
88- } ) ;
89140
90- setCSVColumnMap ( columnMap ) ;
141+ setCSVColumnMap ( columnMap ) ;
91142
92- setCSVContents ( {
93- ...results ,
94- meta : {
95- ...results . meta ,
96- fields : [ ...new Set ( results . meta . fields ) ] ,
97- } ,
98- } ) ;
99- } ,
100- } ) ;
143+ setCSVContents ( {
144+ ...results ,
145+ meta : {
146+ ...results . meta ,
147+ fields : [ ...new Set ( results . meta . fields || [ ] ) ] ,
148+ } ,
149+ } ) ;
150+ } ,
151+ } ) ;
152+ }
101153 } ;
102154
103155 fileReader . readAsText ( file ) ;
104156 }
105157 } ;
106158
107- const onGenerateCompetitorAssignments = ( props ?: any ) => {
159+ const onGenerateCompetitorAssignments = ( ) => {
160+ if ( ! wcif || ! CSVContents ) return ;
161+
108162 try {
109163 const assignments = generateAssignments ( wcif , CSVContents ) ;
110164 setCompetitorAssignments ( assignments ) ;
@@ -115,11 +169,13 @@ const ImportPage = (props?: any) => {
115169 setAssignmentGenerationError ( null ) ;
116170 } catch ( e ) {
117171 console . error ( e ) ;
118- setAssignmentGenerationError ( e ) ;
172+ setAssignmentGenerationError ( e as Error ) ;
119173 }
120174 } ;
121175
122- const onGenerateMissingGroupActivities = ( props ?: any ) => {
176+ const onGenerateMissingGroupActivities = ( ) => {
177+ if ( ! wcif || ! missingGroupActivities ) return ;
178+
123179 try {
124180 dispatch (
125181 partialUpdateWCIF ( {
@@ -130,14 +186,16 @@ const ImportPage = (props?: any) => {
130186 } )
131187 ) ;
132188
133- setMissingGroupActivities ( null ) ;
189+ setMissingGroupActivities ( undefined ) ;
134190 } catch ( e ) {
135191 console . error ( e ) ;
136- setAssignmentGenerationError ( e ) ;
192+ setAssignmentGenerationError ( e as Error ) ;
137193 }
138194 } ;
139195
140- const onImportCompetitorAssignments = ( props ?: any ) => {
196+ const onImportCompetitorAssignments = ( ) => {
197+ if ( ! wcif || ! competitorAssignments ) return ;
198+
141199 const newWcif = upsertCompetitorAssignments (
142200 wcif ,
143201 determineStageForAssignments ( wcif , competitorAssignments )
@@ -223,19 +281,19 @@ const ImportPage = (props?: any) => {
223281 </ Button >
224282 </ form >
225283 </ Grid >
226- { CSVContents && (
284+ { CSVContents && validation && (
227285 < >
228286 < Divider />
229287 < br />
230288 < Grid >
231289 < Typography variant = "h5" > Checks</ Typography >
232- { validation . map ( ( check , index ) => (
290+ { validation . map ( ( check : ValidationCheck , index : number ) => (
233291 < Alert key = { check . key + index } severity = { check . passed ? 'success' : 'error' } >
234292 { check . message }
235293 < br />
236294 { check . data &&
237295 check . key === 'has-all-competing-event-column' &&
238- check . data . map ( ( i ) => i . email ) . join ( ', ' ) }
296+ check . data . map ( ( i : CSVRow ) => i . email ) . join ( ', ' ) }
239297 </ Alert >
240298 ) ) }
241299 </ Grid >
@@ -279,7 +337,7 @@ const ImportPage = (props?: any) => {
279337 < Button
280338 variant = "contained"
281339 disabled = {
282- ! ! competitorAssignments ?. length || validation . some ( ( check ) => ! check . passed )
340+ ! ! competitorAssignments ?. length || validation . some ( ( check : ValidationCheck ) => ! check . passed )
283341 }
284342 onClick = { onGenerateCompetitorAssignments } >
285343 GENERATE COMPETITOR ASSIGNMENTS
@@ -307,7 +365,7 @@ const ImportPage = (props?: any) => {
307365 < Button
308366 variant = "contained"
309367 disabled = {
310- ( missingGroupActivities && missingGroupActivities . length ) ||
368+ ( missingGroupActivities && missingGroupActivities . length > 0 ) ||
311369 ! competitorAssignments ?. length
312370 }
313371 onClick = { onImportCompetitorAssignments } >
0 commit comments