@@ -4,7 +4,8 @@ import { Avatar, Button, CircularProgress, styled } from "@mui/material";
44import Box from "@mui/material/Box" ;
55import { useSnackbar } from "notistack" ;
66import 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";
89import GithubSignIn from "../components/GithubSignIn" ;
910import GoogleSignIn from "../components/GoogleSignIn" ;
1011import "../components/css/EditorComponent.css" ;
@@ -22,6 +23,7 @@ import {
2223} from "../constants/constants" ;
2324import { useAuth } from "../context/AuthContext" ;
2425import Footer from "../components/Footer" ;
26+ // import FileUploadIcon from "@mui/icons-material/FileUpload";
2527
2628const StyledButton = styled ( Button ) ( {
2729 display : "flex" ,
@@ -101,6 +103,8 @@ function EditorComponent() {
101103 } ;
102104
103105 useEffect ( ( ) => {
106+ if ( isImportingRef . current ) return ;
107+
104108 const selectedLanguage = LANGUAGES . find (
105109 ( lang ) => lang . DEFAULT_LANGUAGE === currentLanguage
106110 ) ;
@@ -206,6 +210,92 @@ function EditorComponent() {
206210 }
207211 } , [ enqueueSnackbar , languageDetails ] ) ;
208212
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+ isImportingRef . current = false ;
246+ setIsImporting ( false ) ;
247+ return ;
248+ }
249+ const reader = new FileReader ( ) ;
250+ reader . onload = ( event ) => {
251+ setCurrentLanguage ( selectedLanguage . DEFAULT_LANGUAGE ) ;
252+ setLanguageDetails ( {
253+ ID : selectedLanguage . ID ,
254+ NAME : selectedLanguage . NAME ,
255+ DEFAULT_LANGUAGE : selectedLanguage . DEFAULT_LANGUAGE ,
256+ LANGUAGE_NAME : selectedLanguage . NAME ,
257+ } ) ;
258+ setCode ( event . target . result ) ;
259+ // console.log("file code ", event.target.result);
260+ setOutput ( "" ) ;
261+ setIsImporting ( false ) ;
262+ } ;
263+ reader . onerror = ( ) => {
264+ console . error ( "Error reading file" ) ;
265+ isImportingRef . current = false ;
266+ setIsImporting ( false ) ;
267+ } ;
268+ reader . readAsText ( file ) ;
269+ } ;
270+
271+ // download file
272+ const exportFile = ( ) => {
273+ if ( ! code ) return ;
274+
275+ const fileContent = code ;
276+
277+ const extensionMap = {
278+ javascript : "js" ,
279+ python : "py" ,
280+ cpp : "cpp" ,
281+ java : "java" ,
282+ } ;
283+
284+ const extension = extensionMap [ languageDetails . DEFAULT_LANGUAGE ] || "txt" ;
285+
286+ const blob = new Blob ( [ fileContent ] , { type : "text/plain" } ) ;
287+ const url = URL . createObjectURL ( blob ) ;
288+ const link = document . createElement ( "a" ) ;
289+
290+ link . href = url ;
291+ link . download = `code.${ extension } ` ;
292+ document . body . appendChild ( link ) ;
293+ link . click ( ) ;
294+
295+ document . body . removeChild ( link ) ;
296+ URL . revokeObjectURL ( url ) ;
297+ } ;
298+
209299 const handleEditorDidMount = useCallback (
210300 ( editor , monaco ) => {
211301 console . log ( "Editor mounted" ) ; // Debug log
@@ -244,6 +334,7 @@ function EditorComponent() {
244334 } , [ handleEditorDidMount ] ) ;
245335
246336 function handleLanguageChange ( _ , value ) {
337+ if ( isImporting ) return ;
247338 setCurrentLanguage ( value . DEFAULT_LANGUAGE ) ;
248339 setOutput ( "" ) ;
249340 setCode ( code ? code : value . HELLO_WORLD ) ;
@@ -273,6 +364,110 @@ function EditorComponent() {
273364 className = "sidebar"
274365 style = { { display : "flex" , flexDirection : "column" } }
275366 >
367+ { /* import and export btn */ }
368+ < div style = { { display : "flex" , flexDirection : "row" , gap : "0.5rem" } } >
369+ < StyledButton
370+ onClick = { ( ) => fileInputRef . current . click ( ) }
371+ disabled = { isImporting }
372+ sx = { ( theme ) => ( {
373+ padding : "8px 10px" ,
374+ backgroundColor : theme . palette . primary . main ,
375+ color : theme . palette . primary . contrastText ,
376+ border : `1px solid ${ theme . palette . primary . dark } ` ,
377+ borderRadius : "8px" ,
378+ fontSize : "0.875rem" ,
379+ fontWeight : 500 ,
380+ cursor : "pointer" ,
381+ boxShadow : "0 2px 4px rgba(0, 0, 0, 0.08)" ,
382+ transition : "all 0.2s ease" ,
383+ display : "flex" ,
384+ alignItems : "center" ,
385+ justifyContent : "center" ,
386+ gap : "8px" ,
387+ "&:hover" : {
388+ backgroundColor : theme . palette . primary . dark ,
389+ boxShadow : "0 4px 8px rgba(0, 0, 0, 0.12)" ,
390+ transform : "translateY(-1px)" ,
391+ } ,
392+ "&:active" : {
393+ transform : "translateY(0)" ,
394+ boxShadow : "0 2px 4px rgba(0, 0, 0, 0.1)" ,
395+ } ,
396+ "&:disabled" : {
397+ backgroundColor : theme . palette . action . disabled ,
398+ color : theme . palette . action . disabledBackground ,
399+ cursor : "not-allowed" ,
400+ transform : "none" ,
401+ } ,
402+ "@media (max-width: 768px)" : {
403+ padding : "8px 12px" ,
404+ fontSize : "0.8125rem" ,
405+ } ,
406+ } ) }
407+ >
408+ { isImporting ? (
409+ < >
410+ < CircularProgress size = { 16 } color = "inherit" />
411+ Importing...
412+ </ >
413+ ) : (
414+ < >
415+ < FaFileUpload fontSize = "small" />
416+ Import
417+ </ >
418+ ) }
419+ </ StyledButton >
420+ < input
421+ type = "file"
422+ ref = { fileInputRef }
423+ style = { { display : "none" } }
424+ accept = ".java,.js,.py,.cpp"
425+ onChange = { handleFileImport }
426+ />
427+
428+ < StyledButton
429+ onClick = { exportFile }
430+ sx = { ( theme ) => ( {
431+ padding : "8px 10px" ,
432+ backgroundColor : theme . palette . primary . main ,
433+ color : theme . palette . primary . contrastText ,
434+ border : `1px solid ${ theme . palette . primary . dark } ` ,
435+ borderRadius : "8px" ,
436+ fontSize : "0.875rem" ,
437+ fontWeight : 500 ,
438+ cursor : "pointer" ,
439+ boxShadow : "0 2px 4px rgba(0, 0, 0, 0.08)" ,
440+ transition : "all 0.2s ease" ,
441+ display : "flex" ,
442+ alignItems : "center" ,
443+ justifyContent : "center" ,
444+ gap : "8px" ,
445+ "&:hover" : {
446+ backgroundColor : theme . palette . primary . dark ,
447+ boxShadow : "0 4px 8px rgba(0, 0, 0, 0.12)" ,
448+ transform : "translateY(-1px)" ,
449+ } ,
450+ "&:active" : {
451+ transform : "translateY(0)" ,
452+ boxShadow : "0 2px 4px rgba(0, 0, 0, 0.1)" ,
453+ } ,
454+ "&:disabled" : {
455+ backgroundColor : theme . palette . action . disabled ,
456+ color : theme . palette . action . disabledBackground ,
457+ cursor : "not-allowed" ,
458+ transform : "none" ,
459+ } ,
460+ "@media (max-width: 768px)" : {
461+ padding : "8px 12px" ,
462+ fontSize : "0.8125rem" ,
463+ } ,
464+ } ) }
465+ >
466+ < FaFileDownload fontSize = "small" />
467+ Export
468+ </ StyledButton >
469+ </ div >
470+
276471 { getLanguageLogoById ( languageDetails . ID ) }
277472 < div style = { { fontWeight : "bold" } } >
278473 { languageDetails . LANGUAGE_NAME }
0 commit comments