import React , { useContext , useRef , useState } from 'react' ; import { Importer as Import , ErrMessage } from './index.style' ; import { TasksContext } from "@context/tasks" ; import { TaskInfos } from "@generated/client" ; import { tasksFields as allFields } from "@constants/tasks" ; import XLSX from 'xlsx' ; import { JigSettings } from '@typeDefs/task' ; import Typography from '@material-ui/core/Typography' ; import { generateData } from '@services/faker' ; type ImporterProps = { type : string ; fieldsRequired : string [ ] | undefined ; children : React . ReactNode ; jigActivated : boolean ; jigSettings : JigSettings ; } ; export const Importer = ( { type , fieldsRequired , children , jigActivated , jigSettings } ) => { const [ dragged , setDragged ] = useState ( false ) ; const [ error , setError ] = useState ( "" ) ; const handleDragEnter = ( e ) => { e . preventDefault ( ) ; e . stopPropagation ( ) ; setDragged ( true ) ; setError ( "" ) ; } ; const handleDragLeave = ( e ) => { e . preventDefault ( ) ; e . stopPropagation ( ) ; setDragged ( false ) ; setError ( "" ) ; } ; const handleDragOver = ( e ) => { e . preventDefault ( ) ; e . stopPropagation ( ) ; setDragged ( true ) ; setError ( "" ) ; } ; const handleDrop = ( e ) => { e . preventDefault ( ) ; e . stopPropagation ( ) ; setDragged ( false ) ; setError ( "" ) ; let files = e . dataTransfer . files , f = files [ 0 ] ; let reader = new FileReader ( ) ; reader . onload = async ( e ) => { let data = new Uint8Array ( e . target . result ) ; let workbook = XLSX . read ( data , { type : 'array' } ) ; let data_json = await to_json ( workbook ) ; extract ( data_json ) . then ( list => context . setTasks ( list ) ) . catch ( ( e ) => console . error ( e ) ) ; } ; reader . readAsArrayBuffer ( f ) ; } ; const handleInput = ( e ) => { e . preventDefault ( ) ; e . stopPropagation ( ) ; setError ( "" ) ; if ( fileInput . current && fileInput . current . files ) { let files = fileInput . current . files , f = files [ 0 ] ; let reader = new FileReader ( ) ; reader . onload = async ( e ) => { let data = new Uint8Array ( e . target . result ) ; let workbook = XLSX . read ( data , { type : 'array' } ) ; let data_json = await to_json ( workbook ) ; extract ( data_json ) . then ( list => context . setTasks ( list ) ) . catch ( ( e ) => console . error ( e ) ) ; } ; reader . readAsArrayBuffer ( f ) ; } else { return 0 ; } } ; const to_json = async ( workbook ) => { let result = { } ; workbook . SheetNames . forEach ( ( sheetName ) => { let roa = XLSX . utils . sheet_to_json ( workbook . Sheets [ sheetName ] , { header : 1 } ) ; if ( roa . length ) { result [ sheetName ] = roa ; } } ) ; return result ; } ; const extract = async ( data ) => { let tasks = [ ] ; let xlsx_name = Object . keys ( data ) [ 0 ] ; if ( ! fieldsRequired || fieldsRequired . length == 0 ) { setError ( "Please choose a valid website to import tasks." ) ; throw new Error ( "Please choose a valid website to import tasks." ) ; } let fields = allFields . filter ( e => fieldsRequired . indexOf ( e ) !== - 1 ) ; let excelColumns = [ ] ; let indexsOfNeededColumns = [ ] ; data [ xlsx_name ] . forEach ( ( row , rowIndex ) => { if ( row === [ ] || row . length === 0 ) return tasks ; if ( rowIndex === 0 ) { excelColumns = row ; row = row . filter ( column => fields . indexOf ( column . toLowerCase ( ) ) !== - 1 ) ; fields = fields . slice ( ) . sort ( ) ; row = row . slice ( ) . sort ( ( a , b ) => a . toLowerCase ( ) . localeCompare ( b . toLowerCase ( ) ) ) ; if ( fields . length !== row . length || ! fields . every ( ( value , index ) => value . toLowerCase ( ) === row [ index ] . toLowerCase ( ) ) ) { for ( let i = 0 ; i < fields . length ; i ++ ) { if ( fields [ i ] . toLowerCase ( ) !== row [ i ] . toLowerCase ( ) ) { console . error ( `${ fields [ i ] . toLowerCase ( ) } != ${ row [ i ] . toLowerCase ( ) }` ) ; let _error = `Missing column inside the Excel: have you forgot "${ fields [ i ] }"?` ; setError ( _error ) ; throw new Error ( _error ) ; } } } for ( let i = 0 ; i < row . length ; i ++ ) { indexsOfNeededColumns . push ( excelColumns . indexOf ( row [ i ] ) ) ; } } else { let task = { size : "" , fname : "" , lname : "" , email : "" } ; for ( let index of indexsOfNeededColumns ) { if ( row [ index ] === null || row [ index ] === undefined ) { if ( jigActivated ) { try { row [ index ] = generateData ( excelColumns [ index ] . toLowerCase ( ) , jigSettings . locale ) ; } catch ( error ) { let _error = `Could not generate data at row: ${ rowIndex + 1 } | column: "${ excelColumns [ index ] }. ${ error }"` ; setError ( _error ) ; throw new Error ( _error ) ; } } else { let _error = `Missing data at row: ${ rowIndex + 1 } | column: "${ excelColumns [ index ] }". If you want to auto generate data, consider checking the box below to activate data auto-generation.` ; setError ( _error ) ; throw new Error ( _error ) ; } } task [ excelColumns [ index ] . toLowerCase ( ) ] = row [ index ] . toString ( ) ; } tasks . push ( task ) ; } } ) ; console . log ( tasks ) ; return tasks ; } ; const context = useContext ( TasksContext ) ; const fileInput = useRef < HTMLInputElement > ( null ) ; return ( < Import onDrop = { e => handleDrop ( e ) } onDragOver = { e => handleDragOver ( e ) } onDragEnter = { e => handleDragEnter ( e ) } onDragLeave = { e => handleDragLeave ( e ) } dragged = { dragged } > { children } < br / > Import { type } < br />Drag and drop Excel files (.xlsx)<br / > { } Download the excel below and fill it < br / > < input type = "file" ref = { fileInput } onChange = { ( e ) => handleInput ( e ) } /> { error !== "" ? < ErrMessage > ERROR < br / > { error } < /ErrMessage> : null } < /Import>); } ;