├── .gitignore ├── README.md ├── api ├── app.js ├── index.js ├── modules │ └── index.js ├── package.json └── routes │ └── index.js ├── judge ├── app.js ├── config.js ├── index.js ├── modules │ ├── commands.js │ ├── evaluateCode.js │ ├── getData.js │ └── runCode.js ├── package.json └── routes │ └── index.js ├── online-compiler ├── .eslintrc.json ├── README.md ├── components │ ├── Login │ │ ├── header │ │ │ └── Header.js │ │ └── signin │ │ │ └── SigninComponent.js │ ├── Problem │ │ ├── description │ │ │ └── DescriptionComponent.js │ │ ├── hints │ │ │ └── HintsComponent.js │ │ ├── ide │ │ │ ├── IdeComponent.js │ │ │ └── modules.js │ │ └── submission │ │ │ └── SubmissionComponent.js │ ├── loading │ │ └── LoadingComponents.js │ └── styles │ │ ├── Description.module.css │ │ ├── Header.module.css │ │ ├── Hints.module.css │ │ ├── Ide.module.css │ │ ├── Signin.module.css │ │ ├── Statement.module.css │ │ ├── Submission.module.css │ │ └── loading.module.css ├── modules │ └── getData.js ├── next.config.js ├── package.json ├── pages │ ├── [pid].js │ ├── _app.js │ └── index.js ├── public │ ├── description.svg │ ├── favicon.ico │ └── vercel.svg └── styles │ ├── Home.module.css │ ├── globals.css │ └── pid.module.css └── pictures ├── login.PNG ├── problem.png ├── problemList.PNG └── screenshot.png /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | online-compiler/node_modules 3 | online-compiler/.pnp 4 | online-compiler/.pnp.js 5 | 6 | # testing 7 | online-compiler/coverage 8 | 9 | # next.js 10 | online-compiler/.next/ 11 | online-compiler/out/ 12 | 13 | # production 14 | online-compiler/build 15 | 16 | # misc 17 | online-compiler/.DS_Store 18 | online-compiler/*.pem 19 | 20 | # debug 21 | online-compiler/npm-debug.log* 22 | online-compiler/yarn-debug.log* 23 | online-compiler/yarn-error.log* 24 | online-compiler/.pnpm-debug.log* 25 | 26 | # local env files 27 | online-compiler/.env.local 28 | online-compiler/.env.development.local 29 | online-compiler/.env.test.local 30 | online-compiler/.env.production.local 31 | online-compiler/config.js 32 | 33 | # vercel 34 | online-compiler/.vercel 35 | online-compiler/yarn.lock 36 | 37 | # judge 38 | judge/.env 39 | judge/package-lock.json 40 | judge/yarn.lock 41 | judge/node_modules 42 | 43 | # api 44 | api/modules/online-compiler.json 45 | api/package-lock.json 46 | api/yarn.lock 47 | api/node_modules 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Leetcode Clone 2 | 3 | ## Description 4 | 5 | Online Judge Compiler is Leetcode tiny version. The app is divided in **Frontend ide**, **judge api** and **problem api**. 6 | 7 | ## Setup 8 | 9 | > api 10 | 11 | Default port: 5050 12 | 13 | The api is using firebase store as database, to store test cases and evaluator of each problem. 14 | 15 | Base structure 16 | 17 | ```javascript 18 | { 19 | "problems": { 20 | "name_problem_1": { 21 | "extension_language": [ /* ONLY C++ and Javascript are available (as cpp and js) */ 22 | "simple test case", 23 | "evaluator code", 24 | "correct answer", 25 | "complete test case" 26 | ], 27 | } 28 | }, 29 | "statements": { 30 | "name_problem_1": { 31 | "title": "Name Problem 1", 32 | "hints": [], 33 | "input": "simple test case", 34 | "statement": "html description problem", 35 | "templates": [ 36 | "solution file empty for cpp", 37 | "solution file empty for js" 38 | ], 39 | } 40 | } 41 | } 42 | ``` 43 | 44 | Include Service Account Key in /api/modules as "online-compiler.json" 45 | 46 | > judge 47 | 48 | Default port: 3080 49 | 50 | Judge api needs docker installed 51 | 52 | Create .env file with the following keys 53 | 54 | ```sh 55 | PROBLEM_API='your_api_url' 56 | JUDGE_PATH='your_path_to_store_the_code_of_users' 57 | ``` 58 | 59 | > Client 60 | 61 | Export Firebase SDK app in /online-compiler/config.js 62 | 63 | Default port: 3000 64 | 65 | ## Install & Run 66 | 67 | Valid for each application 68 | 69 | ```sh 70 | yarn 71 | yarn dev 72 | ``` 73 | 74 | ## Preview 75 | 76 | ![pic1](/pictures/login.PNG) 77 | ![pic2](/pictures/problemList.PNG) 78 | ![pic3](/pictures/problem.png) 79 | ![pic4](/pictures/screenshot.png) 80 | -------------------------------------------------------------------------------- /api/app.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import cors from 'cors'; 3 | import helmet from 'helmet'; 4 | import routes from './routes/index.js'; 5 | import firestore from './modules/index.js'; 6 | 7 | const app = express(); 8 | 9 | app.use(cors()); 10 | app.use(helmet()); 11 | app.use(express.json()); 12 | app.use(express.urlencoded({ extended: true })); 13 | app.use('/', routes); 14 | 15 | (function () { 16 | const database = firestore(); 17 | app.set('firestore', database); 18 | })(); 19 | 20 | export default app; 21 | -------------------------------------------------------------------------------- /api/index.js: -------------------------------------------------------------------------------- 1 | import app from './app.js'; 2 | 3 | const PORT = process.env.PORT || 5050; 4 | 5 | app.listen(PORT, () => console.log('[api] Running on port', PORT)); 6 | -------------------------------------------------------------------------------- /api/modules/index.js: -------------------------------------------------------------------------------- 1 | import { initializeApp, cert } from 'firebase-admin/app'; 2 | import { getFirestore } from 'firebase-admin/firestore'; 3 | import serviceAcc from './online-compiler.json'; 4 | 5 | export default function firestore() { 6 | initializeApp({ 7 | credential: cert(serviceAcc), 8 | }); 9 | 10 | const db = getFirestore(); 11 | 12 | return { 13 | async getProblem (id) { 14 | const docRef = await db.collection('problems').doc(id).get(); 15 | return docRef._fieldsProto; 16 | }, 17 | 18 | async getStatement (id) { 19 | const docRef = await db.collection('statements').doc(id).get(); 20 | return docRef._fieldsProto; 21 | }, 22 | 23 | async getProblemList () { 24 | const docRef = await db.collection('statements').get(); 25 | return docRef; 26 | }, 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api", 3 | "version": "1.0.0", 4 | "description": "api problems for judge", 5 | "type": "module", 6 | "main": "index.js", 7 | "scripts": { 8 | "dev": "node --experimental-json-modules index.js" 9 | }, 10 | "license": "MIT", 11 | "dependencies": { 12 | "cors": "^2.8.5", 13 | "express": "^4.17.3", 14 | "firebase-admin": "^10.0.2", 15 | "helmet": "^5.0.2" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /api/routes/index.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | 3 | const app = express.Router(); 4 | 5 | app.get('/problems', async (req, res) => { 6 | const firestore = req.app.get('firestore'); 7 | 8 | try { 9 | const problemList = await firestore.getProblemList(); 10 | const statements = []; 11 | 12 | problemList.forEach((doc) => statements.push({ id: doc.id, title: doc.data().title })); 13 | 14 | res.json(statements); 15 | } catch (error) { 16 | res.sendStatus(404); 17 | } 18 | }); 19 | 20 | app.get('/problem/:id', async (req, res) => { 21 | const { id } = req.params; 22 | const firestore = req.app.get('firestore'); 23 | 24 | try { 25 | const statement = await firestore.getStatement(id); 26 | 27 | res.json(statement); 28 | } catch (error) { 29 | res.sendStatus(404); 30 | } 31 | }); 32 | 33 | app.get('/evaluator/:id/:language/:mode', async (req, res) => { 34 | const { id, language, mode } = req.params; 35 | const firestore = req.app.get('firestore'); 36 | 37 | try { 38 | const data = await firestore.getProblem(id); 39 | const evaluators = data[language].arrayValue.values; 40 | 41 | const evaluator = { 42 | evaluator: evaluators[1].stringValue.split('_n').join('\n'), 43 | correct: evaluators[2].stringValue.split('_n').join('\n'), 44 | input: mode === 'run' ? evaluators[0].stringValue : data.cpp.arrayValue.values[3].stringValue, 45 | }; 46 | 47 | res.json(evaluator); 48 | } catch (error) { 49 | res.sendStatus(404); 50 | } 51 | }); 52 | 53 | export default app; 54 | -------------------------------------------------------------------------------- /judge/app.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import cors from 'cors'; 3 | import helmet from 'helmet'; 4 | import runCodeRoute from './routes/index.js'; 5 | 6 | const app = express(); 7 | 8 | app.use(cors()); 9 | app.use(helmet()); 10 | app.use(express.json()); 11 | app.use(express.urlencoded({ extended: true })); 12 | app.use('/', runCodeRoute); 13 | 14 | export default app; 15 | -------------------------------------------------------------------------------- /judge/config.js: -------------------------------------------------------------------------------- 1 | import 'dotenv/config'; 2 | 3 | const vars = { 4 | problemApi: process.env.PROBLEM_API, 5 | judgePath: process.env.JUDGE_PATH, 6 | }; 7 | 8 | export default vars; 9 | -------------------------------------------------------------------------------- /judge/index.js: -------------------------------------------------------------------------------- 1 | import app from './app.js'; 2 | 3 | const PORT = process.env.PORT || 3080; 4 | app.listen(PORT, () => console.log('[server] Running on port:', PORT)); 5 | -------------------------------------------------------------------------------- /judge/modules/commands.js: -------------------------------------------------------------------------------- 1 | export default function commands(path, id) { 2 | return { 3 | cpp: `docker run --rm -m 64M --memory-swap 64M --name ${id} -v ${path}:/code -w /code cpp /bin/sh -c "g++ -Wall main.cpp -o a && ./a >&1 | tee"`, 4 | js: `docker run --rm -m 64M --memory-swap 64M --name ${id} -v ${path}:/code -w /code node:current-alpine3.15 /bin/sh -c "node main.js"`, 5 | }; 6 | } 7 | -------------------------------------------------------------------------------- /judge/modules/evaluateCode.js: -------------------------------------------------------------------------------- 1 | import { createFolder, createFiles, runCode, deleteFolder } from './runCode.js'; 2 | import commands from './commands.js'; 3 | import config from '../config.js'; 4 | 5 | const { judgePath } = config; 6 | 7 | export default async function evaluateCode(id, code, language, { evaluator, correct, input }) { 8 | const fullPath = `${judgePath}\\${id}`; 9 | 10 | try { 11 | const cmd = commands(fullPath, id)[language]; 12 | 13 | await createFolder(judgePath, id); 14 | await createFiles( 15 | fullPath, 16 | { name: `\\input.txt`, string: input }, 17 | { name: `\\main.${language}`, string: evaluator }, 18 | { name: `\\Correct.${language}`, string: correct }, 19 | { name: `\\Solution.${language}`, string: code }, 20 | ); 21 | const output = await runCode(cmd, 15000, id); 22 | await deleteFolder(fullPath); 23 | 24 | return output; 25 | } catch (error) { 26 | await deleteFolder(fullPath); 27 | if (typeof error === 'string') 28 | return error; 29 | 30 | return 'Out of Memory'; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /judge/modules/getData.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import config from '../config.js'; 3 | 4 | const { problemApi } = config; 5 | 6 | export default async function getEvaluator(id, language, mode /* run | submit */) { 7 | return axios.get(`${problemApi}/evaluator/${id}/${language}/${mode}`); 8 | } 9 | -------------------------------------------------------------------------------- /judge/modules/runCode.js: -------------------------------------------------------------------------------- 1 | import { writeFile } from 'fs'; 2 | import { exec } from 'child_process'; 3 | 4 | export const createFolder = (path, name) => { 5 | return new Promise((resolve, reject) => { 6 | exec(`cd ${path} && mkdir ${name}`, (err, _, __) => { 7 | if (err) return reject(err); 8 | resolve(); 9 | }); 10 | }); 11 | }; 12 | 13 | export const createFiles = (path, input, evaluator, correct, main) => { 14 | return new Promise((resolve, reject) => { 15 | const writeSolutionFile = () => { 16 | writeFile(path.concat(main.name), main.string, (err) => { 17 | if (err) return reject(err); 18 | resolve(); 19 | }); 20 | }; 21 | 22 | const writeCorrectFile = () => { 23 | writeFile(path.concat(correct.name), correct.string, (err) => { 24 | if (err) return reject(err); 25 | writeSolutionFile(); 26 | }); 27 | }; 28 | 29 | const writeEvaluatorFile = () => { 30 | writeFile(path.concat(evaluator.name), evaluator.string, (err) => { 31 | if (err) return reject(err); 32 | writeCorrectFile(); 33 | }); 34 | }; 35 | 36 | const writeInputFile = () => { 37 | writeFile(path.concat(input.name), input.string, (err) => { 38 | if (err) return reject(err); 39 | writeEvaluatorFile(); 40 | }); 41 | }; 42 | 43 | writeInputFile(); 44 | }); 45 | }; 46 | 47 | export const runCode = (cmd, timeout, name) => { 48 | return new Promise((resolve, reject) => { 49 | exec(cmd, { timeout, killSignal: 'SIGKILL' }, (err, stdout, stderr) => { 50 | if (stderr) { 51 | if (stderr.startsWith('docker: Error response from daemon: OCI runtime')) 52 | reject('Out of Memory 64MB'); 53 | else 54 | reject(stderr); 55 | } 56 | 57 | if (err) { 58 | if (err.killed) { 59 | exec(`docker kill ${name}`); 60 | resolve(`${stdout} \nTimeout after ${timeout}ms`) 61 | } else 62 | reject(err); 63 | } else { 64 | resolve(stdout); 65 | } 66 | }); 67 | }); 68 | }; 69 | 70 | export const deleteFolder = (path) => { 71 | return new Promise((resolve, reject) => { 72 | exec(`rm -rf ${path}`, (err, _, __) => { 73 | if (err) return reject(err); 74 | resolve(); 75 | }); 76 | }); 77 | }; 78 | -------------------------------------------------------------------------------- /judge/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "judge", 3 | "version": "1.0.0", 4 | "description": "jugde for online compiler", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "dev": "node --experimental-json-modules index.js" 9 | }, 10 | "license": "MIT", 11 | "private": true, 12 | "dependencies": { 13 | "axios": "^0.26.0", 14 | "cors": "^2.8.5", 15 | "dotenv": "^16.0.0", 16 | "express": "^4.17.3", 17 | "firebase-admin": "^10.0.2", 18 | "helmet": "^5.0.2" 19 | }, 20 | "devDependencies": { 21 | "nodemon": "^2.0.15" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /judge/routes/index.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import getEvaluator from '../modules/getData.js'; 3 | import evaluateCode from '../modules/evaluateCode.js'; 4 | 5 | const app = express.Router(); 6 | 7 | app.post('/', async (req, res) => { 8 | const { id, code, language, problem } = req.body; 9 | 10 | if (!id || !code || !language) { return res.sendStatus(400); } 11 | 12 | try { 13 | const getData = await getEvaluator(problem, language, 'run'); 14 | const { evaluator, correct, input } = getData.data; 15 | const output = await evaluateCode(id, code, language, { evaluator, correct, input }); 16 | 17 | res.json(output); 18 | } catch (error) { 19 | res.send(error); 20 | } 21 | }); 22 | 23 | app.post('/judge', async (req, res) => { 24 | const { id, code, language, problem } = req.body; 25 | 26 | if (!id || !code || !language) { return res.sendStatus(400); } 27 | 28 | try { 29 | const getData = await getEvaluator(problem, language, 'submit'); 30 | const { evaluator, correct, input } = getData.data; 31 | const output = await evaluateCode(id, code, language, { evaluator, correct, input }); 32 | 33 | if (output.includes('correct:true')) 34 | res.send('Accepted'); 35 | else if (output.includes('correct:false')) 36 | res.send('Wrong Answer'); 37 | else if (output.includes('Timeout after')) 38 | res.send('Time Limited Exceded'); 39 | else 40 | res.send(output); 41 | } catch (error) { 42 | await deleteFolder(fullPath); 43 | if (typeof error === 'string') 44 | return res.send(error); 45 | 46 | res.send('Out of Memory'); 47 | } 48 | }); 49 | 50 | export default app; 51 | -------------------------------------------------------------------------------- /online-compiler/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /online-compiler/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | ``` 12 | 13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 14 | 15 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. 16 | 17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`. 18 | 19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy on Vercel 31 | 32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 33 | 34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 35 | -------------------------------------------------------------------------------- /online-compiler/components/Login/header/Header.js: -------------------------------------------------------------------------------- 1 | import { signOut } from "firebase/auth"; 2 | import styles from '../../styles/Header.module.css'; 3 | 4 | export default function Header ({ auth, children }) { 5 | const handleClick = (e) => { 6 | e.preventDefault(); 7 | const userLogout = confirm('Are you sure?'); 8 | 9 | if (userLogout) { 10 | signOut(auth); 11 | } 12 | }; 13 | 14 | return ( 15 |
16 | Logout 21 | {children} 22 |
23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /online-compiler/components/Login/signin/SigninComponent.js: -------------------------------------------------------------------------------- 1 | import { GoogleAuthProvider, getAuth, signInWithPopup } from 'firebase/auth'; 2 | import { useState } from 'react'; 3 | import { firebaseApp } from '../../../config'; 4 | import styles from '../../styles/Signin.module.css'; 5 | 6 | export default function Signin() { 7 | const [loading, setLoading] = useState(false); 8 | 9 | const handleClick = async () => { 10 | const auth = getAuth(firebaseApp()); 11 | const googleProvider = new GoogleAuthProvider(); 12 | try { 13 | setLoading(true); 14 | await signInWithPopup(auth, googleProvider); 15 | } catch (error) { 16 | console.error(error); 17 | } finally { 18 | setLoading(false); 19 | } 20 | }; 21 | 22 | return ( 23 |
24 | 29 |
30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /online-compiler/components/Problem/description/DescriptionComponent.js: -------------------------------------------------------------------------------- 1 | import Image from 'next/image'; 2 | import styles from '../../styles/Description.module.css'; 3 | 4 | export default function DescriptionComponent({ children, title }) { 5 | return ( 6 |
7 |
8 | ⬅ | 9 | desc 10 |

{title}

11 |
12 | 13 |
14 | {children} 15 |
16 |
17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /online-compiler/components/Problem/hints/HintsComponent.js: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import styles from '../../styles/Hints.module.css'; 3 | 4 | export default function HintsComponent({ hints = [] }) { 5 | const [open, toggleOpen] = useState(new Array(hints.length).fill(false)); 6 | 7 | const handleToggle = (index) => { 8 | const copy = [...open]; 9 | copy[index] = !copy[index]; 10 | 11 | toggleOpen(copy); 12 | }; 13 | 14 | return ( 15 |
16 | {hints.map((hint, index) => ( 17 |
handleToggle(index)}> 18 | 19 | 💡 {open[index] ? 'Hide' : 'Show'} hint #{index + 1} 20 | 21 | {hint} 22 |
23 | ))} 24 |
25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /online-compiler/components/Problem/ide/IdeComponent.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react'; 2 | import Editor from '@monaco-editor/react'; 3 | import SubmissionComponent from '../submission/SubmissionComponent'; 4 | import styles from '../../styles/Ide.module.css'; 5 | import { runCode, submitCode } from './modules'; 6 | 7 | export default function IdeComponent({ templates, input, problemId, userId }) { 8 | // editor 9 | const [language, setLanguage] = useState('cpp'); 10 | const [template, setTemplate] = useState('// some code here'); 11 | const [theme, setTheme] = useState('vs-light'); 12 | const [themeButton, setThemeButton] = useState('🌞'); 13 | const [code, setCode] = useState(''); 14 | const [extension, setExtension] = useState('cpp'); 15 | 16 | // submissions 17 | const [loading, setLoading] = useState(false); 18 | const [submission, setSubmission] = useState(''); 19 | const [result, setResults] = useState(''); 20 | const [typeSubmission, setTypeSubmission] = useState(''); 21 | 22 | useEffect(() => { 23 | setTemplate(templates[0] || '// some code here'); 24 | setCode(templates[0] || '// some code here'); 25 | }, [templates, input, problemId, userId]); 26 | 27 | const handleChangeTheme = (e) => { 28 | e.preventDefault(); 29 | 30 | if (themeButton === '🌞') { 31 | setTheme('vs-dark'); 32 | setThemeButton('🌙'); 33 | return; 34 | } 35 | setTheme('vs-light'); 36 | setThemeButton('🌞'); 37 | }; 38 | 39 | const handleChangeLanguage = (e) => { 40 | const lang = e.target.value; 41 | if (lang === 'js') { 42 | setExtension('js'); 43 | setLanguage('javascript'); 44 | setTemplate(templates[1]); 45 | setCode(templates[1]); 46 | } else if (lang === 'cpp') { 47 | setExtension('cpp'); 48 | setLanguage('cpp'); 49 | setTemplate(templates[0]); 50 | setCode(templates[0]); 51 | } 52 | }; 53 | 54 | const handleRunCode = async () => { 55 | try { 56 | setLoading(true); 57 | await runCode( 58 | code, 59 | extension, 60 | problemId, 61 | setSubmission, 62 | setResults, 63 | setTypeSubmission, 64 | userId, 65 | ); 66 | } finally { 67 | setLoading(false); 68 | } 69 | }; 70 | 71 | const handleSubmitCode = async () => { 72 | try { 73 | setLoading(true); 74 | await submitCode( 75 | code, 76 | extension, 77 | problemId, 78 | setSubmission, 79 | setResults, 80 | setTypeSubmission, 81 | userId, 82 | ); 83 | } finally { 84 | setLoading(false); 85 | } 86 | }; 87 | 88 | return ( 89 |
90 |
91 |
92 | 101 | 102 | {themeButton} 103 |
104 | 105 | setCode(value)} 112 | /> 113 | 114 |
115 |
116 | 122 | 128 |
129 |
130 | 131 |
132 | 133 | {submission.length > 1 ? ( 134 | 140 | ) : null} 141 |
142 | ); 143 | } 144 | -------------------------------------------------------------------------------- /online-compiler/components/Problem/ide/modules.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | const uri = 'http://localhost:3080'; 4 | 5 | export async function submitCode(code, language, problem, setSubmission, setResults, setTypeSubmission, userId) { 6 | setTypeSubmission('submit'); 7 | setSubmission('Pending'); 8 | try { 9 | const output = await axios.post(`${uri}/judge`, { 10 | id: userId, 11 | code, 12 | language, 13 | problem, 14 | }); 15 | 16 | const outputData = output.data; 17 | if (outputData === 'Time Limited Exceded' || outputData === 'Accepted' || outputData === 'Wrong Answer' || outputData === 'Out of Memory') { 18 | setSubmission(outputData); 19 | setResults(null); 20 | } else { 21 | setSubmission('Runtime Error'); 22 | setResults(outputData); 23 | } 24 | } catch (err) { 25 | setSubmission('Server Error'); 26 | setResults(null); 27 | } 28 | } 29 | 30 | export async function runCode(code, language, problem, setSubmission, setResults, setTypeSubmission, userId) { 31 | setTypeSubmission('run'); 32 | setSubmission('Pending'); 33 | try { 34 | const output = await axios.post(`${uri}`, { 35 | id: userId, 36 | code, 37 | language, 38 | problem, 39 | }); 40 | 41 | let outputData = output.data; 42 | 43 | if (output.data.includes('Timeout after')) { 44 | setSubmission('Time Limited Exceded'); 45 | } else { 46 | if (output.data.startsWith('solution:')) { 47 | if (output.data.includes('correct:true')) { 48 | setSubmission('Accepted'); 49 | outputData = outputData 50 | .replace('solution:', '') 51 | .replace('correct:true', ''); 52 | } else if (output.data.includes('correct:false')) { 53 | setSubmission('Wrong Answer'); 54 | outputData = outputData 55 | .replace('solution:', '') 56 | .replace('correct:false', ''); 57 | } 58 | } else { 59 | if (output.data === 'Out of Memory') { 60 | setSubmission('Out of Memory'); 61 | } else { 62 | setSubmission('Runtime Error'); 63 | } 64 | } 65 | } 66 | 67 | setResults(outputData.replace('solution:', '')); 68 | } catch (error) { 69 | console.log(error); 70 | setSubmission('Server Error'); 71 | setResults(null); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /online-compiler/components/Problem/submission/SubmissionComponent.js: -------------------------------------------------------------------------------- 1 | import styles from '../../styles/Submission.module.css'; 2 | 3 | export default function SubmissionComponent ({ status, input, output, type }) { 4 | // status -> Pending | TimeLimitedExceded | RuntimeError | WrongAnswer | Accepted | Out of Memory 5 | const style = status.split(' ').join(''); 6 | const typeSubmission = type[0].toUpperCase().concat(type.substring(1)); 7 | 8 | return ( 9 |
10 |

{typeSubmission} Code Status: {status}

11 | 12 | {status !== 'Pending' && !!output ? ( 13 |
14 | {type === 'run' ? ( 15 |
16 | Input 17 |
{input.split('\n').map((str,i) =>

{str}

)}
18 |
19 | ) : null} 20 | 21 | {output ? ( 22 |
23 | Your Answer 24 |
{output.split('\n').map((str,i) =>

{str}

)}
25 |
26 | ) : null} 27 |
28 | ) : null} 29 |
30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /online-compiler/components/loading/LoadingComponents.js: -------------------------------------------------------------------------------- 1 | import styles from '../styles/loading.module.css'; 2 | 3 | export default function Loading() { 4 | return ( 5 |
6 |
7 |
8 | ); 9 | } -------------------------------------------------------------------------------- /online-compiler/components/styles/Description.module.css: -------------------------------------------------------------------------------- 1 | .title { 2 | padding-top: 2%; 3 | margin-top: 0; 4 | margin-left: 10px; 5 | } 6 | 7 | .problem { 8 | padding: 15px; 9 | border-radius: 10px; 10 | background-color: white; 11 | } 12 | 13 | .title_container { 14 | display: flex; 15 | flex-direction: row; 16 | align-items: center; 17 | } 18 | -------------------------------------------------------------------------------- /online-compiler/components/styles/Header.module.css: -------------------------------------------------------------------------------- 1 | .button { 2 | float: right; 3 | margin: 20px 20px; 4 | font-weight: bold; 5 | } -------------------------------------------------------------------------------- /online-compiler/components/styles/Hints.module.css: -------------------------------------------------------------------------------- 1 | .details { 2 | margin-top: 10px; 3 | margin-bottom: 10px; 4 | padding: 10px; 5 | background-color: white; 6 | border: 1px solid #cccccc; 7 | border-radius: 3px; 8 | } 9 | 10 | .details:hover { 11 | cursor: pointer; 12 | border: 1px solid #10009c; 13 | border-radius: 3px; 14 | } 15 | 16 | .details:hover > .summary { 17 | color: #10009c; 18 | } 19 | -------------------------------------------------------------------------------- /online-compiler/components/styles/Ide.module.css: -------------------------------------------------------------------------------- 1 | .config { 2 | margin-top: 10px; 3 | margin-bottom: 10px; 4 | display: flex; 5 | justify-content: space-between; 6 | } 7 | 8 | .line { 9 | border: 1px solid #cccccc; 10 | } 11 | 12 | .select { 13 | padding: 10px; 14 | border: 1px solid #cccccc; 15 | border-radius: 3px; 16 | font-weight: bold; 17 | } 18 | 19 | .select:hover { 20 | cursor: pointer; 21 | } 22 | 23 | .theme { 24 | padding: 10px; 25 | background-color: white; 26 | border: 1px solid #cccccc; 27 | border-radius: 3px; 28 | } 29 | 30 | .theme:hover { 31 | background-color: #cccccc; 32 | } 33 | 34 | .compile { 35 | margin-top: 10px; 36 | display: flex; 37 | justify-content: flex-end; 38 | } 39 | 40 | .buttons { 41 | margin-bottom: 10px; 42 | } 43 | 44 | .run_button { 45 | border: 1px solid #cccccc; 46 | padding: 10px; 47 | border-radius: 100px; 48 | background-color: white; 49 | margin-right: 10px; 50 | font-size: 14px; 51 | font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace; 52 | } 53 | 54 | .run_button:hover { 55 | cursor: pointer; 56 | background-color: #cccccc; 57 | } 58 | 59 | .submit_button { 60 | border: 1px solid #10009c; 61 | padding: 10px; 62 | border-radius: 100px; 63 | background-color: #10009c; 64 | color: white; 65 | font-size: 14px; 66 | font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace; 67 | } 68 | 69 | .submit_button:hover { 70 | cursor: pointer; 71 | background-color: #3c2fb3; 72 | } 73 | -------------------------------------------------------------------------------- /online-compiler/components/styles/Signin.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | min-height: 100vh; 3 | display: flex; 4 | justify-content: center; 5 | align-items: center; 6 | } 7 | 8 | .button { 9 | border: none; 10 | padding: 15px 30px; 11 | color: white; 12 | background: tomato; 13 | cursor: pointer; 14 | border-radius: 8px; 15 | font-weight: bold; 16 | font-size: 18px; 17 | } 18 | -------------------------------------------------------------------------------- /online-compiler/components/styles/Statement.module.css: -------------------------------------------------------------------------------- 1 | .code { 2 | padding: 10px; 3 | margin-top: 10px; 4 | background-color: #F5F5F5; 5 | border: 1px solid #cccccc; 6 | border-radius: 3px; 7 | font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace; 8 | font-size: 14px; 9 | } 10 | 11 | .sub { 12 | font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace; 13 | color: #C7254E; 14 | background-color: #F9F2F4; 15 | border-radius: 3px; 16 | } 17 | -------------------------------------------------------------------------------- /online-compiler/components/styles/Submission.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | margin-top: 20px; 3 | background-color: white; 4 | padding: 15px; 5 | border-radius: 10px; 6 | } 7 | 8 | .Accepted { color: green; } 9 | .Pending { color: blue; } 10 | .TimeLimitedExceded, .RuntimeError, .WrongAnswer, .ServerError, .OutofMemory { color: red; } 11 | 12 | .code { 13 | padding: 10px; 14 | margin-top: 10px; 15 | background-color: #F5F5F5; 16 | border: 1px solid #cccccc; 17 | border-radius: 3px; 18 | font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace; 19 | font-size: 14px; 20 | } 21 | 22 | .results div { 23 | margin-top: 15px; 24 | } 25 | -------------------------------------------------------------------------------- /online-compiler/components/styles/loading.module.css: -------------------------------------------------------------------------------- 1 | .loading { 2 | display: inline-block; 3 | position: relative; 4 | width: 80px; 5 | height: 80px; 6 | } 7 | .loading div { 8 | display: inline-block; 9 | position: absolute; 10 | left: 8px; 11 | width: 16px; 12 | background: grey; 13 | animation: loading 1.2s cubic-bezier(0, 0.5, 0.5, 1) infinite; 14 | } 15 | .loading div:nth-child(1) { 16 | left: 8px; 17 | animation-delay: -0.24s; 18 | } 19 | .loading div:nth-child(2) { 20 | left: 32px; 21 | animation-delay: -0.12s; 22 | } 23 | .loading div:nth-child(3) { 24 | left: 56px; 25 | animation-delay: 0; 26 | } 27 | @keyframes loading { 28 | 0% { 29 | top: 8px; 30 | height: 64px; 31 | } 32 | 50%, 100% { 33 | top: 24px; 34 | height: 32px; 35 | } 36 | } -------------------------------------------------------------------------------- /online-compiler/modules/getData.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | export const getProblemList = async (setStatements, setLoading) => { 4 | try { 5 | const res = await axios.get('http://localhost:5050/problems'); 6 | setStatements([...res.data]); 7 | } catch (error) { 8 | console.error(error); 9 | } finally { 10 | setLoading(false); 11 | } 12 | }; 13 | 14 | export const getProblem = async (setLoading, setStatement, pid) => { 15 | if (!pid) return; 16 | 17 | try { 18 | const res = await axios.get(`http://localhost:5050/problem/${pid}`); 19 | setStatement({ 20 | title: res.data.title.stringValue, 21 | statement: res.data.statement.stringValue, 22 | hints: res.data.hints.arrayValue.values.map((value) => value.stringValue), 23 | templates: res.data.templates.arrayValue.values.map( 24 | (value) => value.stringValue.split('_n').join('\n'), 25 | ), 26 | input: res.data.input.stringValue.split('_n').join('\n'), 27 | }); 28 | } catch (error) { 29 | console.error(error); 30 | } finally { 31 | setLoading(false); 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /online-compiler/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | } 5 | 6 | module.exports = nextConfig 7 | -------------------------------------------------------------------------------- /online-compiler/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "online-compiler", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@monaco-editor/react": "^4.3.1", 13 | "axios": "^0.26.0", 14 | "firebase": "^9.6.7", 15 | "next": "12.1.0", 16 | "react": "17.0.2", 17 | "react-dom": "17.0.2" 18 | }, 19 | "devDependencies": { 20 | "eslint": "8.9.0", 21 | "eslint-config-next": "12.1.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /online-compiler/pages/[pid].js: -------------------------------------------------------------------------------- 1 | import { useRouter } from 'next/router'; 2 | import { useEffect, useState } from 'react'; 3 | import { getProblem } from '../modules/getData'; 4 | import styles from '../styles/pid.module.css' 5 | import DescriptionComponent from '../components/Problem/description/DescriptionComponent'; 6 | import HintsComponent from '../components/Problem/hints/HintsComponent'; 7 | import IdeComponent from '../components/Problem/ide/IdeComponent'; 8 | import LoadingComponent from '../components/loading/LoadingComponents'; 9 | 10 | export default function Problem({ userId }) { 11 | const router = useRouter(); 12 | const { pid } = router.query; 13 | 14 | const [loading, setLoading] = useState(true); 15 | const [statement, setStatement] = useState({}); 16 | 17 | useEffect(() => { 18 | getProblem(setLoading, setStatement, pid); 19 | }, [pid]); 20 | 21 | return ( 22 |
23 | {!!statement.title && !loading ? ( 24 |
25 | 26 |
27 |
28 | 29 | 30 | 31 | 37 |
38 | ) : ( 39 |
40 | 41 |
42 | )} 43 |
44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /online-compiler/pages/_app.js: -------------------------------------------------------------------------------- 1 | import { getAuth, onAuthStateChanged } from 'firebase/auth'; 2 | import { useEffect, useState } from 'react'; 3 | import { firebaseApp } from '../config'; 4 | import '../styles/globals.css' 5 | import Signin from '../components/Login/signin/SigninComponent'; 6 | import Header from '../components/Login/header/Header'; 7 | import Loading from '../components/loading/LoadingComponents'; 8 | 9 | function MyApp({ Component, pageProps }) { 10 | const [loading, setLoading] = useState(true); 11 | const [user, setUser] = useState(null); 12 | const [authApp, setAuthApp] = useState(null); 13 | 14 | useEffect(() => { 15 | firebaseApp(); 16 | const auth = getAuth(); 17 | setAuthApp(auth); 18 | 19 | onAuthStateChanged(auth, (user) => { 20 | setUser(user); 21 | setLoading(false); 22 | }); 23 | }, []); 24 | 25 | const signinOrHome = user ? ( 26 |
27 | 28 |
29 | ) : ; 30 | 31 | return ( 32 |
33 | {loading ? ( 34 |
35 | 36 |
37 | ) : signinOrHome} 38 |
39 | ); 40 | } 41 | 42 | export default MyApp; 43 | -------------------------------------------------------------------------------- /online-compiler/pages/index.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | import styles from '../styles/Home.module.css' 3 | import LoadingComponent from '../components/loading/LoadingComponents'; 4 | import { getProblemList } from '../modules/getData'; 5 | 6 | export default function Home() { 7 | const [loading, setLoading] = useState(true); 8 | const [statements, setStatements] = useState([]); 9 | 10 | useEffect(() => { 11 | getProblemList(setStatements, setLoading); 12 | }, []); 13 | 14 | return ( 15 |
16 |
17 | Problems 18 |
19 | {loading ? ( 20 |
21 | 22 |
23 | ) : ( 24 |
25 | {statements.map((statement) => { 26 | return ( 27 |
28 | 📄 {statement.title} 29 |
30 | ); 31 | })} 32 |
33 | )} 34 |
35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /online-compiler/public/description.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /online-compiler/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/juaniviola/leetcode_clone/c49f63ac750d2fdbb79c4a430b07e096d84ce91c/online-compiler/public/favicon.ico -------------------------------------------------------------------------------- /online-compiler/public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /online-compiler/styles/Home.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | min-height: 100vh; 3 | height: 100%; 4 | background-color: #F5F5F5; 5 | padding: 0 5%; 6 | padding-bottom: 2%; 7 | } 8 | 9 | .loading { 10 | text-align: center; 11 | } 12 | 13 | .title { 14 | font-weight: bold; 15 | font-size: 24px; 16 | padding-top: 50px; 17 | margin-bottom: 30px; 18 | } 19 | 20 | .problem { 21 | padding: 10px; 22 | border: 1px solid black; 23 | background-color: white; 24 | } 25 | 26 | .problem:first-of-type { 27 | border-top-left-radius: 5px; 28 | border-top-right-radius: 5px; 29 | } 30 | 31 | .problem:last-of-type { 32 | border-bottom-left-radius: 5px; 33 | border-bottom-right-radius: 5px; 34 | } 35 | -------------------------------------------------------------------------------- /online-compiler/styles/globals.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | padding: 0; 4 | margin: 0; 5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 7 | } 8 | 9 | body { 10 | min-height: 100vh; 11 | } 12 | 13 | a { 14 | color: inherit; 15 | text-decoration: none; 16 | } 17 | 18 | * { 19 | box-sizing: border-box; 20 | } 21 | -------------------------------------------------------------------------------- /online-compiler/styles/pid.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | min-height: 100vh; 3 | background-color: #F5F5F5; 4 | padding: 0 5%; 5 | padding-bottom: 2%; 6 | } 7 | 8 | .loading { 9 | display: flex; 10 | justify-content: center; 11 | align-items: center; 12 | } 13 | -------------------------------------------------------------------------------- /pictures/login.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/juaniviola/leetcode_clone/c49f63ac750d2fdbb79c4a430b07e096d84ce91c/pictures/login.PNG -------------------------------------------------------------------------------- /pictures/problem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/juaniviola/leetcode_clone/c49f63ac750d2fdbb79c4a430b07e096d84ce91c/pictures/problem.png -------------------------------------------------------------------------------- /pictures/problemList.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/juaniviola/leetcode_clone/c49f63ac750d2fdbb79c4a430b07e096d84ce91c/pictures/problemList.PNG -------------------------------------------------------------------------------- /pictures/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/juaniviola/leetcode_clone/c49f63ac750d2fdbb79c4a430b07e096d84ce91c/pictures/screenshot.png --------------------------------------------------------------------------------