11import './MyOpenCRE.scss' ;
22
3- import React , { useState } from 'react' ;
3+ import React , { useRef , useState } from 'react' ;
44import { Button , Container , Form , Header , Message } from 'semantic-ui-react' ;
55
66import { useEnvironment } from '../../hooks' ;
@@ -19,6 +19,13 @@ type ImportErrorResponse = {
1919 errors ?: RowValidationError [ ] ;
2020} ;
2121
22+ type CsvPreview = {
23+ rows : number ;
24+ creMappings : number ;
25+ uniqueSections : number ;
26+ creColumns : string [ ] ;
27+ } ;
28+
2229export const MyOpenCRE = ( ) => {
2330 const { apiUrl } = useEnvironment ( ) ;
2431
@@ -30,6 +37,10 @@ export const MyOpenCRE = () => {
3037 const [ error , setError ] = useState < ImportErrorResponse | null > ( null ) ;
3138 const [ success , setSuccess ] = useState < any | null > ( null ) ;
3239 const [ info , setInfo ] = useState < string | null > ( null ) ;
40+ const [ preview , setPreview ] = useState < CsvPreview | null > ( null ) ;
41+ const [ confirmedImport , setConfirmedImport ] = useState ( false ) ;
42+
43+ const fileInputRef = useRef < HTMLInputElement > ( null ) ;
3344
3445 /* ------------------ CSV DOWNLOAD ------------------ */
3546
@@ -64,12 +75,60 @@ export const MyOpenCRE = () => {
6475 }
6576 } ;
6677
78+ /* ------------------ CSV PREVIEW ------------------ */
79+
80+ const generateCsvPreview = async ( file : File ) => {
81+ const text = await file . text ( ) ;
82+ const lines = text . split ( '\n' ) . filter ( Boolean ) ;
83+
84+ if ( lines . length < 2 ) {
85+ setPreview ( null ) ;
86+ return ;
87+ }
88+
89+ const headers = lines [ 0 ] . split ( ',' ) . map ( ( h ) => h . trim ( ) ) ;
90+ const rows = lines . slice ( 1 ) ;
91+
92+ const creColumns = headers . filter ( ( h ) => h . startsWith ( 'CRE' ) ) ;
93+ let creMappings = 0 ;
94+ const sectionSet = new Set < string > ( ) ;
95+
96+ rows . forEach ( ( line ) => {
97+ const values = line . split ( ',' ) ;
98+ const rowObj : Record < string , string > = { } ;
99+
100+ headers . forEach ( ( h , i ) => {
101+ rowObj [ h ] = ( values [ i ] || '' ) . trim ( ) ;
102+ } ) ;
103+
104+ const name = ( rowObj [ 'standard|name' ] || '' ) . trim ( ) ;
105+ const id = ( rowObj [ 'standard|id' ] || '' ) . trim ( ) ;
106+
107+ if ( name || id ) {
108+ sectionSet . add ( `${ name } |${ id } ` ) ;
109+ }
110+
111+ creColumns . forEach ( ( col ) => {
112+ if ( rowObj [ col ] ) creMappings += 1 ;
113+ } ) ;
114+ } ) ;
115+
116+ setPreview ( {
117+ rows : rows . length ,
118+ creMappings,
119+ uniqueSections : sectionSet . size ,
120+ creColumns,
121+ } ) ;
122+ } ;
123+
67124 /* ------------------ FILE SELECTION ------------------ */
68125
69126 const onFileChange = ( e : React . ChangeEvent < HTMLInputElement > ) => {
70127 setError ( null ) ;
71128 setSuccess ( null ) ;
72129 setInfo ( null ) ;
130+ setPreview ( null ) ;
131+ setConfirmedImport ( false ) ;
73132
74133 if ( ! e . target . files || e . target . files . length === 0 ) return ;
75134
@@ -87,12 +146,13 @@ export const MyOpenCRE = () => {
87146 }
88147
89148 setSelectedFile ( file ) ;
149+ generateCsvPreview ( file ) ;
90150 } ;
91151
92152 /* ------------------ CSV UPLOAD ------------------ */
93153
94154 const uploadCsv = async ( ) => {
95- if ( ! selectedFile ) return ;
155+ if ( ! selectedFile || ! confirmedImport ) return ;
96156
97157 setLoading ( true ) ;
98158 setError ( null ) ;
@@ -125,16 +185,25 @@ export const MyOpenCRE = () => {
125185 setInfo (
126186 'Import completed successfully, but no new CREs or standards were added because all mappings already exist.'
127187 ) ;
188+ } else if ( payload . import_type === 'empty' ) {
189+ setInfo ( 'The uploaded CSV did not contain any importable rows. No changes were made.' ) ;
128190 } else {
129191 setSuccess ( payload ) ;
130192 }
131- setSelectedFile ( null ) ;
193+
194+ setConfirmedImport ( false ) ;
195+ setPreview ( null ) ;
196+ if ( fileInputRef . current ) {
197+ fileInputRef . current . value = '' ;
198+ }
132199 } catch ( err : any ) {
133200 setError ( {
134201 success : false ,
135202 type : 'CLIENT_ERROR' ,
136203 message : err . message || 'Unexpected error during import' ,
137204 } ) ;
205+ setPreview ( null ) ;
206+ setConfirmedImport ( false ) ;
138207 } finally {
139208 setLoading ( false ) ;
140209 }
@@ -211,15 +280,62 @@ export const MyOpenCRE = () => {
211280 </ Message >
212281 ) }
213282
283+ { confirmedImport && ! loading && ! success && ! error && (
284+ < Message positive >
285+ CSV validated successfully. Click < strong > Upload CSV</ strong > to start importing.
286+ </ Message >
287+ ) }
288+
289+ { preview && (
290+ < Message info className = "myopencre-preview" >
291+ < strong > Import Preview</ strong >
292+ < ul >
293+ < li > Rows detected: { preview . rows } </ li >
294+ < li > CRE mappings found: { preview . creMappings } </ li >
295+ < li > Unique standard sections: { preview . uniqueSections } </ li >
296+ < li > CRE columns detected: { preview . creColumns . join ( ', ' ) } </ li >
297+ </ ul >
298+
299+ < Button
300+ primary
301+ size = "small"
302+ onClick = { ( ) => {
303+ setPreview ( null ) ;
304+ setConfirmedImport ( true ) ;
305+ } }
306+ >
307+ Confirm Import
308+ </ Button >
309+
310+ < Button
311+ size = "small"
312+ onClick = { ( ) => {
313+ setPreview ( null ) ;
314+ setConfirmedImport ( false ) ;
315+ setSelectedFile ( null ) ;
316+ if ( fileInputRef . current ) fileInputRef . current . value = '' ;
317+ } }
318+ >
319+ Cancel
320+ </ Button >
321+ </ Message >
322+ ) }
323+
214324 < Form >
215325 < Form . Field >
216- < input type = "file" accept = ".csv" disabled = { ! isUploadEnabled || loading } onChange = { onFileChange } />
326+ < input
327+ ref = { fileInputRef }
328+ type = "file"
329+ accept = ".csv"
330+ disabled = { ! isUploadEnabled || loading || ! ! preview }
331+ onChange = { onFileChange }
332+ />
217333 </ Form . Field >
218334
219335 < Button
220336 primary
221337 loading = { loading }
222- disabled = { ! isUploadEnabled || ! selectedFile || loading }
338+ disabled = { ! isUploadEnabled || ! selectedFile || ! confirmedImport || loading }
223339 onClick = { uploadCsv }
224340 >
225341 Upload CSV
0 commit comments