@@ -12,7 +12,11 @@ import {
1212 Icon ,
1313 Alert ,
1414} from '@openedx/paragon' ;
15- import { Upload , InsertDriveFile , CheckCircle } from '@openedx/paragon/icons' ;
15+ import {
16+ Upload ,
17+ LibraryBooks ,
18+ AccessTime ,
19+ } from '@openedx/paragon/icons' ;
1620import { Formik } from 'formik' ;
1721import { useNavigate } from 'react-router-dom' ;
1822import * as Yup from 'yup' ;
@@ -135,7 +139,7 @@ export const CreateLibrary = ({
135139 } ) ;
136140 } else {
137141 // Call handleError for invalid file types
138- handleError ( new Error ( 'Invalid file type. Please upload a .zip, .tar.gz, or .tar file.' ) ) ;
142+ handleError ( new Error ( intl . formatMessage ( messages . invalidFileTypeError ) ) ) ;
139143 }
140144 }
141145 } , [ restoreMutation ] ) ;
@@ -169,7 +173,7 @@ export const CreateLibrary = ({
169173 { /* Archive upload section - shown above form when in archive mode */ }
170174 { isFromArchive && (
171175 < div className = "mb-4" >
172- { ! uploadedFile && (
176+ { ! uploadedFile && ! restoreMutation . isPending && (
173177 < Dropzone
174178 data-testid = "library-archive-dropzone"
175179 accept = { {
@@ -182,7 +186,7 @@ export const CreateLibrary = ({
182186 style = { { height : '300px' } }
183187 errorMessages = { {
184188 invalidSize : intl . formatMessage ( messages . dropzoneSubtitle ) ,
185- multipleDragged : 'Please upload only one archive file.' ,
189+ multipleDragged : intl . formatMessage ( messages . dropzoneMultipleDraggedError ) ,
186190 } }
187191 >
188192 < Stack direction = "vertical" gap = { 3 } className = "text-center" >
@@ -195,46 +199,53 @@ export const CreateLibrary = ({
195199 </ Dropzone >
196200 ) }
197201
198- { uploadedFile && restoreStatus ?. state === LibraryRestoreStatus . Succeeded && restoreStatus . result && (
199- // Show restore result data when succeeded
200- < Card className = "mb-4" >
201- < Card . Body >
202- < Stack direction = "horizontal" gap = { 3 } className = "align-items-center" >
203- < Icon src = { CheckCircle } style = { { height : '40px' , width : '40px' , color : 'green' } } />
204- < div className = "flex-grow-1" >
205- < h5 className = "mb-1" > { restoreStatus . result . title } </ h5 >
206- < p className = "text-muted mb-1" >
207- { restoreStatus . result . org } / { restoreStatus . result . slug }
208- </ p >
209- < p className = "text-muted mb-0 small" >
210- Contains { restoreStatus . result . components } Components •
211- Backed up { new Date ( restoreStatus . result . created_at ) . toLocaleDateString ( ) } at{ ' ' }
212- { new Date ( restoreStatus . result . created_at ) . toLocaleTimeString ( ) }
213- </ p >
214- </ div >
215- </ Stack >
216- </ Card . Body >
217- </ Card >
202+ { /* Loading state - show spinner in DropZone-like container */ }
203+ { restoreMutation . isPending && (
204+ < div
205+ className = "border border-2 border-dashed border-light-400 d-flex align-items-center justify-content-center"
206+ style = { {
207+ height : '300px' ,
208+ borderRadius : '8px' ,
209+ backgroundColor : '#f8f9fa' ,
210+ } }
211+ >
212+ < div className = "spinner-border text-primary" role = "status" style = { { width : '3rem' , height : '3rem' } } >
213+ < span className = "sr-only" > { intl . formatMessage ( messages . uploadingStatus ) } </ span >
214+ </ div >
215+ </ div >
218216 ) }
219217
220- { uploadedFile && restoreStatus ?. state !== LibraryRestoreStatus . Succeeded && (
221- // Show uploaded file info during processing
218+ { uploadedFile && restoreStatus ?. state === LibraryRestoreStatus . Succeeded && restoreStatus . result && (
219+ // Show restore result data when succeeded
222220 < Card className = "mb-4" >
223221 < Card . Body >
224- < Stack direction = "horizontal" gap = { 3 } className = "align-items-center" >
225- < Icon src = { InsertDriveFile } style = { { height : '40px' , width : '40px' } } />
222+ < div className = "d-flex justify-content-between align-items-start p-4" >
226223 < div className = "flex-grow-1" >
227- < h5 className = "mb-1 " > { uploadedFile . name } </ h5 >
224+ < h4 className = "mb-2 " > { restoreStatus . result . title } </ h4 >
228225 < p className = "text-muted mb-0" >
229- { ( uploadedFile . size / ( 1024 * 1024 ) ) . toFixed ( 2 ) } MB
226+ { restoreStatus . result . org } / { restoreStatus . result . slug }
230227 </ p >
231228 </ div >
232- { restoreMutation . isPending && (
233- < div className = "spinner-border spinner-border-sm text-primary" role = "status" >
234- < span className = "sr-only" > Processing...</ span >
229+ < div className = "d-flex flex-column gap-2 align-items-end" >
230+ < div className = "d-flex align-items-center gap-2" >
231+ < Icon src = { LibraryBooks } style = { { width : '20px' , height : '20px' } } />
232+ < span >
233+ { intl . formatMessage ( messages . archiveComponentsCount , {
234+ count : restoreStatus . result . components ,
235+ } ) }
236+ </ span >
235237 </ div >
236- ) }
237- </ Stack >
238+ < div className = "d-flex align-items-center gap-2" >
239+ < Icon src = { AccessTime } style = { { width : '20px' , height : '20px' } } />
240+ < span >
241+ { intl . formatMessage ( messages . archiveBackupDate , {
242+ date : new Date ( restoreStatus . result . created_at ) . toLocaleDateString ( ) ,
243+ time : new Date ( restoreStatus . result . created_at ) . toLocaleTimeString ( ) ,
244+ } ) }
245+ </ span >
246+ </ div >
247+ </ div >
248+ </ div >
238249 </ Card . Body >
239250 </ Card >
240251 ) }
0 commit comments