@@ -4,7 +4,8 @@ import { Avatar, Button, CircularProgress, styled } from "@mui/material";
4
4
import Box from "@mui/material/Box" ;
5
5
import { useSnackbar } from "notistack" ;
6
6
import React , { useCallback , useEffect , useRef , useState } from "react" ;
7
- import { FaPlay } from "react-icons/fa" ;
7
+ import { FaPlay , FaFileUpload , FaFileDownload } from "react-icons/fa" ;
8
+ // import { FaFileUpload } from "react-icons/fa";
8
9
import GithubSignIn from "../components/GithubSignIn" ;
9
10
import GoogleSignIn from "../components/GoogleSignIn" ;
10
11
import "../components/css/EditorComponent.css" ;
@@ -22,6 +23,7 @@ import {
22
23
} from "../constants/constants" ;
23
24
import { useAuth } from "../context/AuthContext" ;
24
25
import Footer from "../components/Footer" ;
26
+ // import FileUploadIcon from "@mui/icons-material/FileUpload";
25
27
26
28
const StyledButton = styled ( Button ) ( {
27
29
display : "flex" ,
@@ -101,6 +103,8 @@ function EditorComponent() {
101
103
} ;
102
104
103
105
useEffect ( ( ) => {
106
+ if ( isImportingRef . current ) return ;
107
+
104
108
const selectedLanguage = LANGUAGES . find (
105
109
( lang ) => lang . DEFAULT_LANGUAGE === currentLanguage
106
110
) ;
@@ -206,6 +210,96 @@ function EditorComponent() {
206
210
}
207
211
} , [ enqueueSnackbar , languageDetails ] ) ;
208
212
213
+ // import file
214
+ const [ isImporting , setIsImporting ] = React . useState ( false ) ;
215
+ const isImportingRef = useRef ( false ) ;
216
+ const fileInputRef = React . useRef ( null ) ;
217
+
218
+ const handleFileImport = ( e ) => {
219
+ const file = e . target . files [ 0 ] ;
220
+ if ( ! file ) return ;
221
+
222
+ setCode ( "" ) ;
223
+ if ( fileInputRef . current ) {
224
+ fileInputRef . current . value = "" ;
225
+ }
226
+
227
+ isImportingRef . current = true ;
228
+ setIsImporting ( true ) ;
229
+
230
+ const extension = file . name . split ( "." ) . pop ( ) . toLowerCase ( ) ;
231
+
232
+ const languageMap = {
233
+ js : "Javascript" ,
234
+ py : "Python3" ,
235
+ cpp : "C++" ,
236
+ java : "Java" ,
237
+ } ;
238
+
239
+ const languageName = languageMap [ extension ] ;
240
+ const selectedLanguage = LANGUAGES . find (
241
+ ( lang ) => lang . NAME === languageName
242
+ ) ;
243
+ if ( ! selectedLanguage ) {
244
+ console . error ( "Unsupported file type" ) ;
245
+ enqueueSnackbar ( "Unsupported file type" , { variant : "error" } ) ;
246
+ isImportingRef . current = false ;
247
+ setIsImporting ( false ) ;
248
+ return ;
249
+ }
250
+ const reader = new FileReader ( ) ;
251
+ reader . onload = ( event ) => {
252
+ setCurrentLanguage ( selectedLanguage . DEFAULT_LANGUAGE ) ;
253
+ setLanguageDetails ( {
254
+ ID : selectedLanguage . ID ,
255
+ NAME : selectedLanguage . NAME ,
256
+ DEFAULT_LANGUAGE : selectedLanguage . DEFAULT_LANGUAGE ,
257
+ LANGUAGE_NAME : selectedLanguage . NAME ,
258
+ } ) ;
259
+ setCode ( event . target . result ) ;
260
+ // console.log("file code ", event.target.result);
261
+ setOutput ( "" ) ;
262
+ setIsImporting ( false ) ;
263
+ } ;
264
+ reader . onerror = ( ) => {
265
+ console . error ( "Error reading file" ) ;
266
+ isImportingRef . current = false ;
267
+ setIsImporting ( false ) ;
268
+ } ;
269
+ reader . readAsText ( file ) ;
270
+ } ;
271
+
272
+ // download file
273
+ const [ isDownloading , setDownloading ] = React . useState ( false ) ;
274
+ const exportFile = ( ) => {
275
+ if ( ! code ) return ;
276
+
277
+ setDownloading ( true ) ;
278
+ const fileContent = code ;
279
+
280
+ const extensionMap = {
281
+ javascript : "js" ,
282
+ python : "py" ,
283
+ cpp : "cpp" ,
284
+ java : "java" ,
285
+ } ;
286
+
287
+ const extension = extensionMap [ languageDetails . DEFAULT_LANGUAGE ] || "txt" ;
288
+
289
+ const blob = new Blob ( [ fileContent ] , { type : "text/plain" } ) ;
290
+ const url = URL . createObjectURL ( blob ) ;
291
+ const link = document . createElement ( "a" ) ;
292
+
293
+ link . href = url ;
294
+ link . download = `code.${ extension } ` ;
295
+ document . body . appendChild ( link ) ;
296
+ link . click ( ) ;
297
+
298
+ document . body . removeChild ( link ) ;
299
+ URL . revokeObjectURL ( url ) ;
300
+ setDownloading ( false ) ;
301
+ } ;
302
+
209
303
const handleEditorDidMount = useCallback (
210
304
( editor , monaco ) => {
211
305
console . log ( "Editor mounted" ) ; // Debug log
@@ -244,6 +338,7 @@ function EditorComponent() {
244
338
} , [ handleEditorDidMount ] ) ;
245
339
246
340
function handleLanguageChange ( _ , value ) {
341
+ if ( isImporting ) return ;
247
342
setCurrentLanguage ( value . DEFAULT_LANGUAGE ) ;
248
343
setOutput ( "" ) ;
249
344
setCode ( code ? code : value . HELLO_WORLD ) ;
@@ -273,6 +368,119 @@ function EditorComponent() {
273
368
className = "sidebar"
274
369
style = { { display : "flex" , flexDirection : "column" } }
275
370
>
371
+ { /* import and export btn */ }
372
+ < div style = { { display : "flex" , flexDirection : "row" , gap : "0.5rem" } } >
373
+ < StyledButton
374
+ onClick = { ( ) => fileInputRef . current . click ( ) }
375
+ disabled = { isImporting }
376
+ sx = { ( theme ) => ( {
377
+ padding : "8px 10px" ,
378
+ backgroundColor : theme . palette . primary . main ,
379
+ color : theme . palette . primary . contrastText ,
380
+ border : `1px solid ${ theme . palette . primary . dark } ` ,
381
+ borderRadius : "8px" ,
382
+ fontSize : "0.875rem" ,
383
+ fontWeight : 500 ,
384
+ cursor : "pointer" ,
385
+ boxShadow : "0 2px 4px rgba(0, 0, 0, 0.08)" ,
386
+ transition : "all 0.2s ease" ,
387
+ display : "flex" ,
388
+ alignItems : "center" ,
389
+ justifyContent : "center" ,
390
+ gap : "8px" ,
391
+ "&:hover" : {
392
+ backgroundColor : theme . palette . primary . dark ,
393
+ boxShadow : "0 4px 8px rgba(0, 0, 0, 0.12)" ,
394
+ transform : "translateY(-1px)" ,
395
+ } ,
396
+ "&:active" : {
397
+ transform : "translateY(0)" ,
398
+ boxShadow : "0 2px 4px rgba(0, 0, 0, 0.1)" ,
399
+ } ,
400
+ "&:disabled" : {
401
+ backgroundColor : theme . palette . action . disabled ,
402
+ color : theme . palette . action . disabledBackground ,
403
+ cursor : "not-allowed" ,
404
+ transform : "none" ,
405
+ } ,
406
+ "@media (max-width: 768px)" : {
407
+ padding : "8px 12px" ,
408
+ fontSize : "0.8125rem" ,
409
+ } ,
410
+ } ) }
411
+ >
412
+ { isImporting ? (
413
+ < >
414
+ < CircularProgress size = { 16 } color = "inherit" />
415
+ Importing...
416
+ </ >
417
+ ) : (
418
+ < >
419
+ < FaFileUpload fontSize = "small" />
420
+ Import
421
+ </ >
422
+ ) }
423
+ </ StyledButton >
424
+ < input
425
+ type = "file"
426
+ ref = { fileInputRef }
427
+ style = { { display : "none" } }
428
+ accept = ".java,.js,.py,.cpp"
429
+ onChange = { handleFileImport }
430
+ />
431
+
432
+ < StyledButton
433
+ onClick = { exportFile }
434
+ sx = { ( theme ) => ( {
435
+ padding : "8px 10px" ,
436
+ backgroundColor : theme . palette . primary . main ,
437
+ color : theme . palette . primary . contrastText ,
438
+ border : `1px solid ${ theme . palette . primary . dark } ` ,
439
+ borderRadius : "8px" ,
440
+ fontSize : "0.875rem" ,
441
+ fontWeight : 500 ,
442
+ cursor : "pointer" ,
443
+ boxShadow : "0 2px 4px rgba(0, 0, 0, 0.08)" ,
444
+ transition : "all 0.2s ease" ,
445
+ display : "flex" ,
446
+ alignItems : "center" ,
447
+ justifyContent : "center" ,
448
+ gap : "8px" ,
449
+ "&:hover" : {
450
+ backgroundColor : theme . palette . primary . dark ,
451
+ boxShadow : "0 4px 8px rgba(0, 0, 0, 0.12)" ,
452
+ transform : "translateY(-1px)" ,
453
+ } ,
454
+ "&:active" : {
455
+ transform : "translateY(0)" ,
456
+ boxShadow : "0 2px 4px rgba(0, 0, 0, 0.1)" ,
457
+ } ,
458
+ "&:disabled" : {
459
+ backgroundColor : theme . palette . action . disabled ,
460
+ color : theme . palette . action . disabledBackground ,
461
+ cursor : "not-allowed" ,
462
+ transform : "none" ,
463
+ } ,
464
+ "@media (max-width: 768px)" : {
465
+ padding : "8px 12px" ,
466
+ fontSize : "0.8125rem" ,
467
+ } ,
468
+ } ) }
469
+ >
470
+ { isDownloading ? (
471
+ < >
472
+ < CircularProgress size = { 16 } color = "inherit" />
473
+ Exporting...
474
+ </ >
475
+ ) : (
476
+ < >
477
+ < FaFileDownload fontSize = "small" />
478
+ Export
479
+ </ >
480
+ ) }
481
+ </ StyledButton >
482
+ </ div >
483
+
276
484
{ getLanguageLogoById ( languageDetails . ID ) }
277
485
< div style = { { fontWeight : "bold" } } >
278
486
{ languageDetails . LANGUAGE_NAME }
0 commit comments