Skip to content

Commit 2de730d

Browse files
committed
file import and export option added
1 parent d3b0317 commit 2de730d

File tree

1 file changed

+196
-1
lines changed

1 file changed

+196
-1
lines changed

src/pages/EditorComponent.js

Lines changed: 196 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import { Avatar, Button, CircularProgress, styled } from "@mui/material";
44
import Box from "@mui/material/Box";
55
import { useSnackbar } from "notistack";
66
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";
89
import GithubSignIn from "../components/GithubSignIn";
910
import GoogleSignIn from "../components/GoogleSignIn";
1011
import "../components/css/EditorComponent.css";
@@ -22,6 +23,7 @@ import {
2223
} from "../constants/constants";
2324
import { useAuth } from "../context/AuthContext";
2425
import Footer from "../components/Footer";
26+
// import FileUploadIcon from "@mui/icons-material/FileUpload";
2527

2628
const 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

Comments
 (0)