├── .github
└── ISSUE_TEMPLATE
│ ├── BUG_REPORT.md
│ └── FEATURE_REQUEST.md
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── backend
└── server
│ ├── Procfile
│ ├── Utils
│ └── Rooms.js
│ ├── index.js
│ ├── package-lock.json
│ ├── package.json
│ └── rateLimiter.js
└── frontend
└── syntaxmeets
├── README.md
├── debug.log
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
├── manifest.json
└── siteimages
│ └── smlogo.png
└── src
├── App.css
├── App.js
├── App.test.js
├── assets
└── css
│ └── sx-chat.css
├── components
├── About
│ ├── About.js
│ ├── About.module.css
│ └── Card
│ │ └── MediaCard.js
├── Footer
│ ├── Footer.js
│ ├── Footer.module.css
│ └── navlogo.png
├── Home
│ ├── Home.js
│ └── Home.module.css
├── Loader
│ ├── Loader.js
│ └── Loader.module.css
├── Mobile
│ ├── Mobile.js
│ └── Mobile.module.css
├── Navbar
│ └── Navbar.js
├── SnackBar
│ └── Snackbar.js
├── SyntaxChat
│ ├── ChatMessage.js
│ ├── ParticipantsList.js
│ └── SyntaxChat.js
├── SyntaxEditor
│ ├── CodeInput.js
│ ├── CodeOutput.js
│ ├── LanguageData.js
│ ├── SyntaxEditor.js
│ └── SyntaxEditor.module.css
├── SyntaxPad
│ ├── SyntaxPad.js
│ └── SyntaxPad.module.css
└── SyntaxRoom
│ └── SyntaxRoom.js
├── images
├── SyntaxMeets.png
├── akash.jpg
├── dhruv.jpg
├── home_svg.svg
├── homepage.svg
├── mobilehome_svg.svg
├── navlogo.png
├── nishant.jpg
└── ogimage.png
├── index.css
├── index.js
├── serviceWorker.js
├── services
├── axios.js
└── socket.js
├── setupTests.js
├── store
├── actions
│ ├── chatActions.js
│ ├── editorActions.js
│ ├── roomActions.js
│ └── uiActions.js
├── reducers
│ ├── chatReducer.js
│ ├── editorReducer.js
│ ├── roomReducer.js
│ └── uiReducer.js
├── store.js
└── types.js
└── util
└── util.js
/.github/ISSUE_TEMPLATE/BUG_REPORT.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report 🐛
3 | about: Something isn't working as expected? Here is the right place to report. For questions, please use "Discussions".
4 | title: ''
5 | labels: 'type:bug'
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | Describe the issue that you're seeing clearly.
12 |
13 | **To Reproduce**
14 | Clear steps describing how to reproduce the issue.
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected result**
21 | What should happen?
22 |
23 | **Actual result**
24 | What happened.
25 |
26 | **Screenshots**
27 | If applicable, add screenshots to help explain your problem.
28 |
29 | **Are you willing to contribute to this issue?** [Yes/No]
30 |
31 | **Desktop (please complete the following information):**
32 | - OS: [e.g. iOS]
33 | - Browser [e.g. chrome, safari]
34 | - Version [e.g. 22]
35 |
36 | **Smartphone (please complete the following information):**
37 | - Device: [e.g. iPhone6]
38 | - OS: [e.g. iOS8.1]
39 | - Browser [e.g. stock browser, safari]
40 | - Version [e.g. 22]
41 |
42 | **Additional context**
43 | Add any other context about the problem here.
44 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request 🌟
3 | about: Suggest new ideas for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Motivation**
17 | Please outline the motivation for the proposal.
18 |
19 | **Are you willing to contribute to this issue?** [Yes/No]
20 |
21 | **Describe alternatives you've considered**
22 | A clear and concise description of any alternative solutions or features you've considered.
23 |
24 | **Additional context**
25 | Add any other context or screenshots about the feature request here.
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | **/node_modules
2 | .vscode
3 | **/.env
4 | .DS_Store
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at kotharidhruv25@gmail.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to SyntaxMeets
2 |
3 | :dizzy::tada: _First of all, thanks for taking the time to contribute!_ :tada::dizzy:
4 |
5 | ---
6 |
7 | ## Contributing Guidelines 📌📌
8 | - Issues will be assigned on a **first come, first serve basis**. You just have to comment on the issue, asking to be assigned, and we'll assign it to you if it's not assigned to anyone else.
9 |
10 | - If you find any **bug** or **feature**, create an issue accordingly, and please wait for it to be **assigned to you**.
11 | - It would be even better if you can visually show a **prototype/animation/design** for any UI improvements you are going to do so that the probability of major changes after writing the code decreases.
12 | - Before creating a Pull Request, please make sure you have **pull the code from origin**, so that **merge conflicts can be prevented.**
13 | - Please remove any **`console logs or errors`** if present in the code(for the sake of debugging), before creating a Pull Request.
14 | - Please write some **comments in the modified section of the code**, so that others can understand you logic and code more easily.
15 | - **Deadlines**: When the issue has been assigned to the user, he/she have to complete the issue within the following assigned time as per the issue level.
16 | - Level 0: 1 Day
17 | - Level 1: 3 Days
18 | - Level 2: 1 Week
19 | - Level 3: 15 Days
20 | ---
21 |
22 | ### ⁉️ Did you find a bug/Issue or an new Feature?, Feel free to submit issues and enhancement requests.
23 |
24 | In general, we follow the "fork-and-pull" Git workflow.
25 |
26 | ---
27 |
28 | ### ✅Following are the steps for Creating Issue -
29 |
30 | ### For creating new issue, select any one of the ISSUE TEMPLATE and describe along with its fields given (\_rather than opening a blank issue*) :
31 |
32 | - Bug Report 🐛
33 | - Feature Request 🌟
34 |
35 | [](https://postimg.cc/dDR9HCPR)
36 |
37 | ---
38 |
39 | ### ✅Following are the steps/rules for Contributing in the project -
40 |
41 | 1. _**Fork**_ the repository on GitHub.
42 |
43 | 2. _**Clone**_ the project (forked copy of the project) to your machine :
44 |
45 | `git clone url-of-forked-project`
46 |
47 | 3. _**Navigate**_ to the directory of project :
48 |
49 | `cd SyntaxMeets`
50 |
51 | 4. Set the _**upstream**_ with original repository :
52 |
53 | `git remote add upstream https://github.com/kothariji/SyntaxMeets.git`
54 |
55 | 5. In order to check associated URLs with the project :
56 |
57 | `git remote -v`
58 |
59 | 6. Before commiting any changes, always _**Pull**_ the upstream so that the recents changes in the original repo gets merged (gets updated with recent changes)
60 |
61 | `git pull upstream master`
62 |
63 | 7. Create a _**New**_ Branch (where you need to push the changes done) and switch to the respective branch :
64 |
65 | `git branch your_branch_name`
66 |
67 | `git checkout -b your_branch_name`
68 |
69 | > NOTE : After cloning into project, in order to run it on the local machine, create .env: file as instructed below :
70 | > create a new .env file in the frontend/syntaxmeets folder and add the following variables -
71 | > REACT_APP_SYNTAXMEETS_BACKEND_API = 'http://localhost:4000/'
72 | > REACT_APP_ONLINE_JUDGE_API = YOUR API KEY
73 |
74 | 8. _**Add**_ and _**Commit**_ your changes with relevant message :
75 |
76 | `git add file_name`
77 |
78 | - While commiting, ensure that you follow the below guidelines :
79 |
80 | - Structure of commit message :
81 | `git commit -m "{{ commit heading }}" -m "{{ commit desc }}"`
82 |
83 | - Commit Headings
84 |
85 | - ⚒️[Fix]: used when we do a css-fix, ui-improvement
86 | - 📚[Docs]: used when modifying/updating docs
87 | - ♻️[Refactor]: used when refacting variables, functions, classes
88 | - 🐛 [Bug]: used when commits related to bug fixed/resolve in process
89 | - 🚀[Feat]: used when adding a new feature in application
90 | - 🔏 [API]: when working with API's
91 |
92 | - When commits are in parts Eg:
93 | - 🌘 [1/3] Auth: setup firebase configs
94 | - 🌗 [2/3] Auth: setup auth routes
95 | - 🌕 [3/3] Auth: finishing with auth functionalities
96 | - Commit Body
97 | - In this we can add a brief description of the modification we did in the code. So overall it would look like -
98 | `git commit -m "🔐[API]: Handle CORS policy" -m "Desc: added Cors libraries to access backend from the react, added whitelist 🔥"`
99 |
100 | 9. _**Push**_ the changes to the same working branch (do not push on _origin_ _master_!)
101 |
102 | `git push -u origin your_branch_name`
103 |
104 | 10. To create a _**Pull request**_ ,click on compare and pull requests.
105 |
106 | 11. Add appropriate _**Title**_ and _**Description**_ explaining the work you have done.
107 |
108 | 12. And Done!! 🥳 Wait till your _**PR**_ gets merged after successful submission! 😄
109 |
110 | ---
111 |
112 | ## Happy Coding 🎯! Keep Contributing ! 🚀
113 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Dhruv Kothari
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # SyntaxMeets
4 | 
5 |
6 |
7 | ### Syntaxmeets. Create rooms 🏠 Call your friends 👬🏼 Sip Chai, ☕ Chat, Create, and Code👨💻. A coding platform to code simultaneously 🚀 with your friends and design your algorithms on SyntaxPad. And you know what's awesome? It's Free.💫✨
8 |
9 | 
10 | [
11 | ](https://github.com/kothariji/SyntaxMeets/issues) [](https://github.com/kothariji/SyntaxMeets)
12 |
13 | [](https://github.com/kothariji/SyntaxMeets) [](https://github.com/kothariji/SyntaxMeets)
14 |
15 |
16 | ---
17 | # Website - [SyntaxMeets](https://syntaxmeets.vercel.app/)
18 |
19 | # Features
20 | - [Create a Room](#Create-a-room-)
21 | - [Join a Room](#Create-a-room-)
22 | - [Syntax Room](#Join-a-room-)
23 | - [SyntaxEditor](#Code-&-Compile-)
24 | - [SyntaxPad](#Syntaxpad-)
25 | - [SyntaxChat](#Code-&-Compile-)
26 |
27 |
28 | ### :rocket:Glimpse :dizzy::dizzy: 
29 |
30 |
31 |
32 |
33 |
34 | ### Creators :zap::dizzy:
35 |
43 |
44 | ### How to Run Locally
45 | Run the below command to clone the repo locally
46 | ```
47 | git clone https://github.com/kothariji/SyntaxMeets.git
48 | ```
49 |
50 | ### To run the server, go to the server folder in the backend directory and Run
51 | ```
52 | npm install
53 | npm start
54 | ```
55 | #### this will run your express server in localhost:4000
56 |
57 | ---
58 | ### To run the application, go to the SyntaxMeets folder in the frontend directory
59 |
60 | create a new .env file and add following variables
61 | ```
62 | REACT_APP_SYNTAXMEETS_BACKEND_API = 'http://localhost:4000/'
63 | REACT_APP_ONLINE_JUDGE_API = YOUR API KEY
64 | ```
65 |
66 | and Run the application using below commands
67 | ```
68 | npm install //install all react dependencies
69 | npm start //runserver
70 | ```
71 | #### this will run your application in localhost:3000
72 |
73 | ### Thank you for Contributing :pray: :dizzy:
74 | 
75 |
76 |
77 | ### If you liked our work do give us a star :star::star::star: It Encourages us to do more :wink: :dizzy:
78 |
--------------------------------------------------------------------------------
/backend/server/Procfile:
--------------------------------------------------------------------------------
1 | web: node index.js
2 |
--------------------------------------------------------------------------------
/backend/server/Utils/Rooms.js:
--------------------------------------------------------------------------------
1 | // Rooms object will store all clients in each room
2 | // in the form of key-value pairs
3 | // example of rooms object :
4 | // this.rooms = {
5 | // id1: {
6 | // {clientid1: name1},
7 | // {clientid2: name2},
8 | // },
9 | // id2: {
10 | // {clientid3: name3},
11 | // {clientid4: name4}
12 | // },
13 | // id3: {
14 | // {clientid5: name5},
15 | // {clientid6: name6},
16 | // {clientid7: name7},
17 | // },
18 | // };
19 |
20 | class Rooms {
21 | constructor() {
22 | this.rooms = {};
23 | }
24 | addUserToRoom(id, name, room) {
25 | if (!this.rooms[room]) {
26 | //Create a new room object
27 | this.rooms[room] = {};
28 | }
29 | //Add user in the room in the form of key-value pair
30 | this.rooms[room][id] = name;
31 | }
32 | getAllUsers(room) {
33 | //return all users in the room using the roomId
34 |
35 | return this.rooms[room];
36 | }
37 | deleteUser(room, id) {
38 | //Delete user from the room
39 | if (this.rooms[room]) {
40 | // from the current room delete key-value of client
41 |
42 | delete this.rooms[room][id];
43 | return id;
44 | }
45 | }
46 | getUser(room) {
47 | let user = {};
48 | //the room dosen't exist
49 | if (!this.rooms[room]) return user;
50 | const keyArray = Object.keys(this.rooms[room]);
51 | //room exists but no user
52 | if (!keyArray.length) return user;
53 | //send old user
54 | //{id:name}
55 | return { [keyArray[0]]: this.rooms[room][keyArray[0]] };
56 | }
57 | }
58 | module.exports = Rooms;
59 |
--------------------------------------------------------------------------------
/backend/server/index.js:
--------------------------------------------------------------------------------
1 | const app = require("express")();
2 | const server = require("http").createServer(app);
3 | const cors = require("cors");
4 | const Rooms = require("./Utils/Rooms");
5 | const io = require("socket.io")(server, { origins: "*:*" });
6 | const helmet = require('helmet');
7 | const rateLimiter = require('./rateLimiter');
8 | // instantiate a new rooms object to store all clients in the room
9 | const rooms = new Rooms();
10 |
11 | // to store all the rooms created
12 | const roomsCreated = [];
13 |
14 | app.use(helmet());
15 |
16 | // io.origins(["http://localhost:3000"]);
17 | app.use(cors());
18 |
19 | io.on("connection" , (socket) => {
20 | let roomId = 0;
21 | let userName = "";
22 | let userId = 1;
23 |
24 | //joining in a room
25 | socket.on("joinroom", function ({ name, room }) {
26 | if (!name) return;
27 |
28 | roomId = room;
29 | userName = name;
30 | userId = socket.id;
31 | // pushes new rooms created in the roomsCreated list
32 | if(!roomsCreated.includes(room))
33 | roomsCreated.push(room);
34 |
35 | socket.join(room);
36 | const oldUser = rooms.getUser(roomId);
37 | rooms.addUserToRoom(socket.id, name, room);
38 | const users = rooms.getAllUsers(room);
39 | // send all the users to only the new User who joined and id of the current user
40 | socket.emit("addusers", { id: socket.id, users });
41 | // inform everyone (excluding the new User) , that a user has been added
42 | // also send the id of an already existing user to the client so only that one
43 | // will emit the code to update for the new user
44 | // console.log(users);
45 | socket.broadcast
46 | .to(roomId)
47 | .emit("userjoined", { newUser: { [socket.id]: name }, oldUser });
48 | });
49 |
50 | socket.on("message", (message) => {
51 | // Send the code in text editor to all the sockets
52 | socket.to(roomId).emit("message", message);
53 | });
54 |
55 | socket.on("typing", (user) => {
56 | // console.log(user);
57 | // inform everyone (excluding the typing user himself) who is typing
58 | socket.broadcast.to(roomId).emit("typing", user);
59 | });
60 | socket.on("chatmessage", (data) => {
61 | // send the chat message to all the users
62 | socket.to(roomId).emit("chatmessage", data);
63 | });
64 |
65 | socket.on("disconnect", function () {
66 | if (!userName) return;
67 |
68 | const returnId = rooms.deleteUser(roomId, socket.id);
69 |
70 | if (returnId)
71 | socket.broadcast
72 | .to(roomId)
73 | .emit("userleft", { id: returnId, name: userName });
74 | });
75 | });
76 |
77 | app.get("/",rateLimiter , (req, res) => {
78 | res.send({ response: "Server is up and Running." }).status(200);
79 | });
80 | // api call to get rooms created
81 | // this api keeps track of active rooms
82 | app.get('/rooms', function(req, res) {
83 | console.log('got the response');
84 | res.json(roomsCreated);
85 | });
86 |
87 | server.listen(process.env.PORT || 4000, function () {
88 | console.log("server is working");
89 | });
90 |
91 |
--------------------------------------------------------------------------------
/backend/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "1.0.0",
4 | "description": "backend for syntaxmeets",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "nodemon index.js"
9 | },
10 | "author": "kothariji, akash, nishant",
11 | "license": "ISC",
12 | "dependencies": {
13 | "cors": "^2.8.5",
14 | "express": "^4.17.1",
15 | "express-rate-limit": "^5.2.6",
16 | "helmet": "^4.4.1",
17 | "nodemon": "^2.0.6",
18 | "socket.io": "^2.4.1"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/backend/server/rateLimiter.js:
--------------------------------------------------------------------------------
1 | const rateLimit = require('express-rate-limit');
2 |
3 | const limit = rateLimit({
4 | windowMs: 1 * 60 * 1000,
5 | max: 100,
6 | message:
7 | "Too many requests created from this IP, please try again after an hour"
8 | });
9 |
10 | module.exports = limit;
--------------------------------------------------------------------------------
/frontend/syntaxmeets/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 |
3 | ## Available Scripts
4 |
5 | In the project directory, you can run:
6 |
7 | ### `npm start`
8 |
9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
11 |
12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console.
14 |
15 | ### `npm test`
16 |
17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
19 |
20 | ### `npm run build`
21 |
22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance.
24 |
25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed!
27 |
28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
29 |
30 | ### `npm run eject`
31 |
32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
33 |
34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
35 |
36 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
37 |
38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
39 |
40 | ## Learn More
41 |
42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
43 |
44 | To learn React, check out the [React documentation](https://reactjs.org/).
45 |
46 | ### Code Splitting
47 |
48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
49 |
50 | ### Analyzing the Bundle Size
51 |
52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
53 |
54 | ### Making a Progressive Web App
55 |
56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
57 |
58 | ### Advanced Configuration
59 |
60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
61 |
62 | ### Deployment
63 |
64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
65 |
66 | ### `npm run build` fails to minify
67 |
68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
69 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/debug.log:
--------------------------------------------------------------------------------
1 | [1125/194413.094:ERROR:directory_reader_win.cc(43)] FindFirstFile: The system cannot find the path specified. (0x3)
2 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "syntaxmeets",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@material-ui/core": "^4.11.0",
7 | "@material-ui/icons": "^4.9.1",
8 | "@material-ui/lab": "^4.0.0-alpha.56",
9 | "@testing-library/jest-dom": "^4.2.4",
10 | "@testing-library/react": "^9.5.0",
11 | "@testing-library/user-event": "^7.2.1",
12 | "ace-builds": "^1.4.12",
13 | "axios": "^0.21.1",
14 | "bootstrap": "^4.5.3",
15 | "copy-to-clipboard": "^3.3.1",
16 | "emoji-mart": "^3.0.1",
17 | "@emotion/react": "^11.7.0",
18 | "fontsource-poppins": "^3.0.9",
19 | "react": "^16.13.1",
20 | "react-ace": "^9.1.4",
21 | "react-awesome-loaders": "^0.1.37",
22 | "react-bootstrap": "^1.4.0",
23 | "react-bootstrap-sweetalert": "^5.2.0",
24 | "react-canvas-draw": "^1.1.1",
25 | "react-color": "^2.19.3",
26 | "react-dom": "^16.13.1",
27 | "react-draggable": "^4.4.3",
28 | "react-loader-spinner": "^3.1.14",
29 | "react-redux": "^7.2.1",
30 | "react-resize-detector": "^5.2.0",
31 | "react-responsive": "^8.1.1",
32 | "react-router-dom": "^5.2.0",
33 | "react-scripts": "^3.4.4",
34 | "react-skylight": "^0.5.1",
35 | "react-modal": "^3.13.1",
36 | "react-spinners": "^0.11.0",
37 | "reactstrap": "^8.9.0",
38 | "redux": "^4.0.5",
39 | "redux-thunk": "^2.3.0",
40 | "responsive-sketchpad": "^1.2.0",
41 | "save": "^2.4.0",
42 | "socket.io-client": "^2.3.1"
43 | },
44 | "scripts": {
45 | "start": "react-scripts start",
46 | "build": "react-scripts build",
47 | "test": "react-scripts test",
48 | "eject": "react-scripts eject"
49 | },
50 | "eslintConfig": {
51 | "extends": "react-app"
52 | },
53 | "browserslist": {
54 | "production": [
55 | ">0.2%",
56 | "not dead",
57 | "not op_mini all"
58 | ],
59 | "development": [
60 | "last 1 chrome version",
61 | "last 1 firefox version",
62 | "last 1 safari version"
63 | ]
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kothariji/SyntaxMeets/74f10e80ae3e42908f9943e27ca06e99a0d53530/frontend/syntaxmeets/public/favicon.ico
--------------------------------------------------------------------------------
/frontend/syntaxmeets/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
10 |
11 |
12 |
13 |
15 |
16 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
31 |
35 |
36 |
45 | SyntaxMeets
46 |
47 |
48 | You need to enable JavaScript to run this app.
49 |
50 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "SyntaxMeets",
3 | "name": "SyntaxMeets",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "theme_color": "#000000",
7 | "background_color": "#ffffff"
8 | }
--------------------------------------------------------------------------------
/frontend/syntaxmeets/public/siteimages/smlogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kothariji/SyntaxMeets/74f10e80ae3e42908f9943e27ca06e99a0d53530/frontend/syntaxmeets/public/siteimages/smlogo.png
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/App.css:
--------------------------------------------------------------------------------
1 | @import "assets/css/sx-chat.css";
2 |
3 | .ace_print-margin {
4 | display: none;
5 | }
6 |
7 | /* scroll--bar styles */
8 | ::-webkit-scrollbar {
9 | width: 15px;
10 | height: 4px;
11 | }
12 |
13 | ::-webkit-scrollbar-track {
14 | background: #000a29;
15 | border-left: 5px solid #000a29;
16 | border-right: 5px solid #000a29;
17 | }
18 |
19 | ::-webkit-scrollbar-thumb {
20 | background-image: linear-gradient(#ffd500, #000a29);
21 | border-left: 5px solid #000a29;
22 | border-right: 5px solid #000a29;
23 | border-radius: 30px;
24 | }
25 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Suspense } from "react";
2 | import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
3 | import "fontsource-poppins";
4 | import "./App.css";
5 | import Loader from "./components/Loader/Loader";
6 | import store from "./store/store";
7 | import { Provider } from "react-redux";
8 | import SnackBar from "./components/SnackBar/Snackbar.js"
9 | const Home = React.lazy(() => import("./components/Home/Home"));
10 | const SyntaxRoom = React.lazy(() =>
11 | import("./components/SyntaxRoom/SyntaxRoom")
12 | );
13 |
14 | const App = () => {
15 | return (
16 |
17 |
18 | }>
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | );
28 | };
29 |
30 | export default App;
31 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/App.test.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kothariji/SyntaxMeets/74f10e80ae3e42908f9943e27ca06e99a0d53530/frontend/syntaxmeets/src/App.test.js
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/assets/css/sx-chat.css:
--------------------------------------------------------------------------------
1 | .sx-chat-message{
2 | color: #fff;
3 | overflow-wrap: break-word;
4 | word-wrap: break-word;
5 | hyphens: auto;
6 | }
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/About/About.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import MediaCard from "./Card/MediaCard";
3 | import { Typography } from "@material-ui/core";
4 | import ArrowBackIcon from '@material-ui/icons/ArrowBack';
5 | import localclasses from "./About.module.css";
6 | import DhruvIMG from "../../images/dhruv.jpg";
7 | import AkashIMG from "../../images/akash.jpg";
8 | import NishantIMG from "../../images/nishant.jpg";
9 |
10 | const About = ({handleClose}) => {
11 | return (
12 |
16 |
17 |
28 |
38 | SyntaxMeets Creators
39 |
40 |
41 |
42 |
52 |
62 |
72 |
73 |
74 | );
75 | };
76 | export default About;
77 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/About/About.module.css:
--------------------------------------------------------------------------------
1 | .aboutus {
2 | background: "#000a29";
3 | width: 100%;
4 | }
5 |
6 | .cards {
7 | margin-left: auto;
8 | margin-right: auto;
9 | background-color: "#000a29";
10 | width: 90%;
11 | padding-top: 5%;
12 | padding-bottom: 5%;
13 | display: flex;
14 | flex-direction: row;
15 | justify-content: space-around;
16 | align-items: inherit;
17 | }
18 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/About/Card/MediaCard.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { makeStyles } from '@material-ui/core/styles';
3 | import Card from '@material-ui/core/Card';
4 | import CardActionArea from '@material-ui/core/CardActionArea';
5 | import CardActions from '@material-ui/core/CardActions';
6 | import CardContent from '@material-ui/core/CardContent';
7 | import CardMedia from '@material-ui/core/CardMedia';
8 | import Typography from '@material-ui/core/Typography';
9 | import LinkedInIcon from '@material-ui/icons/LinkedIn';
10 | import GitHubIcon from '@material-ui/icons/GitHub';
11 | import EmailIcon from '@material-ui/icons/Email';
12 | import TwitterIcon from '@material-ui/icons/Twitter';
13 | import InstagramIcon from '@material-ui/icons/Instagram';
14 |
15 | const useStyles = makeStyles({
16 | root: {
17 | maxWidth: 345,
18 | display: "flex",
19 | flexDirection: "column",
20 | justifyContent: "space-between"
21 | },
22 | media: {
23 | height: 280,
24 | },
25 | icon_card: {
26 | display: "block",
27 | },
28 | icons: {
29 | display: "flex",
30 | justifyContent: "space-around"
31 | }
32 | });
33 |
34 | const MediaCard = (props) => {
35 | const classes = useStyles();
36 |
37 |
38 | return (
39 |
40 |
41 |
46 |
47 |
48 | {props.name}
49 |
50 |
51 | {props.desc}
52 |
53 |
54 |
55 |
56 |
57 | {window.open(props.github)}} />
58 | {window.open(props.twitter)}}/>
59 | {window.open(props.linkedin)}}/>
60 | {window.open(props.gmail)}}/>
61 | {window.open(props.insta)}}/>
62 |
63 |
64 |
65 | );
66 | }
67 |
68 | export default MediaCard;
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/Footer/Footer.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import localclasses from "./Footer.module.css";
3 | import { Row, Col } from "react-bootstrap";
4 | import Button from "@material-ui/core/Button";
5 | import GithubIcon from "@material-ui/icons/GitHub";
6 | import FavoriteIcon from "@material-ui/icons/Favorite";
7 | import GroupIcon from "@material-ui/icons/Group";
8 | import logo from "./navlogo.png";
9 | import About from "../About/About";
10 | import { Dialog, Slide } from "@material-ui/core";
11 |
12 | const Transition = React.forwardRef(function Transition(props, ref) {
13 | return ;
14 | });
15 |
16 | export default function Footer() {
17 | const [open, setOpen] = React.useState(false);
18 |
19 | const handleClickOpen = () => {
20 | setOpen(true);
21 | };
22 | const handleClose = () => {
23 | setOpen(false);
24 | };
25 |
26 | return (
27 |
28 |
35 |
36 |
37 |
38 |
39 |
40 |
45 |
46 |
53 | Syntax
54 |
55 |
62 | Meets
63 |
64 |
65 | SyntaxMeets is a real-time, collaborative coding platform to group
66 | with other members and code. A user can create/join a room. A code
67 | editor with 19 language support and 10+ themes, code compiler,
68 | Drawing pad to design algorithm, Chat Box to discuss and code.
69 |
70 |
71 |
72 |
85 |
86 |
87 |
88 |
89 |
90 |
101 | About Us
102 |
103 |
104 |
110 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
142 |
143 | );
144 | }
145 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/Footer/Footer.module.css:
--------------------------------------------------------------------------------
1 | /*
2 | #000A29, #0077B6,#00B4D8,#FFD500,#F3F7F7,#FFFFFF;
3 | */
4 | .bgblock {
5 | border-radius: 7px;
6 | background-color: #000a29;
7 | font-family: "Poppins";
8 | padding: 4px;
9 | }
10 | .bgblock:hover {
11 | background-color: #001c6d;
12 | }
13 | .footer {
14 | background-color: #000a29;
15 | font-family: "Poppins";
16 | }
17 | .footer_content {
18 | padding: 40px;
19 | color: #dfdddd;
20 | font-size: 0.9em;
21 | margin-right: 0px !important;
22 | }
23 | .footer_content_logo {
24 | padding: 40px;
25 | font-size: 1.3em;
26 | }
27 | .base {
28 | background-color: #f3f7f7;
29 | font-family: "Poppins";
30 | font-size: 0.9em;
31 | padding-top: 11px;
32 | }
33 | .iconGit {
34 | text-decoration: none;
35 | }
36 | .iconGit:hover {
37 | transition: 0.5s;
38 | -webkit-transition: 0.5s;
39 | -moz-transition: 0.5s;
40 | -ms-transition: 0.5s;
41 | -o-transition: 0.5s;
42 | -webkit-transform: rotate(360deg);
43 | -moz-transform: rotate(360deg);
44 | -o-transform: rotate(360deg);
45 | -ms-transform: rotate(360deg);
46 | transform: rotate(360deg);
47 | }
48 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/Footer/navlogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kothariji/SyntaxMeets/74f10e80ae3e42908f9943e27ca06e99a0d53530/frontend/syntaxmeets/src/components/Footer/navlogo.png
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/Home/Home.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useRef,useEffect} from "react";
2 | import localclasses from "./Home.module.css";
3 | import bgimg from "../../images/homepage.svg";
4 | import Container from "react-bootstrap/Container";
5 | import Row from "react-bootstrap/Row";
6 | import Col from "react-bootstrap/Col";
7 | import { TextField, Button as MUIButton, Typography } from "@material-ui/core";
8 | import { Link } from "react-router-dom";
9 | import SkyLight from "react-skylight";
10 | import PropTypes from "prop-types";
11 | import { withStyles } from "@material-ui/core/styles";
12 | import MeetingRoomIcon from "@material-ui/icons/MeetingRoom";
13 | import GroupAddIcon from "@material-ui/icons/GroupAdd";
14 | import { connect } from "react-redux";
15 | import { validateRoomID } from '../../util/util.js'
16 | import * as actions from "../../store/actions/roomActions.js";
17 |
18 | const styles = {
19 | input: {
20 | color: "#000",
21 | },
22 | };
23 |
24 | const Home = (props) => {
25 | const { classes } = props;
26 | const skyLightCreateModal = useRef(SkyLight);
27 | const skyLightJoinModal = useRef(SkyLight);
28 | const [disabledName, setDisabledName] = useState(true);
29 | const [disabledRoomId, setDisabledRoomId] = useState(true);
30 | const createRoomButton = useRef(null);
31 | const joinRoomButton = useRef(null);
32 |
33 |
34 | useEffect(() => {
35 | props.reset();
36 | },[]);
37 |
38 | const roomModal = {
39 | backgroundImage:
40 | "linear-gradient(to top, #d6d4ee, #e1dff2, #ebe9f6, #f5f4fb, #ffffff)",
41 | width: "30%",
42 | marginTop: "-200px",
43 | marginLeft: "-15%",
44 | };
45 |
46 | const ModalTitle = (props) => (
47 |
48 |
56 | {props.start}
57 | Syntax
58 | Room
59 |
60 |
61 | );
62 |
63 | return (
64 |
65 |
66 |
67 |
68 |
73 |
74 |
75 |
76 |
77 | }
90 | size="large"
91 | onClick={() => skyLightCreateModal.current.show()}
92 | >
93 | Create a Room
94 |
95 |
96 |
97 |
98 |
99 | }
111 | size="large"
112 | onClick={() => skyLightJoinModal.current.show()}
113 | >
114 | Join a Room
115 |
116 |
117 |
118 | }
123 | >
124 |
125 |
132 | Enter Your Name
133 |
134 | {
143 | props.setName(e.target.value);
144 | e.target.value.length >= 1
145 | ? setDisabledName(false)
146 | : setDisabledName(true);
147 | }}
148 | onKeyPress={(ev) => {
149 | if(ev.key === 'Enter') {
150 | ev.preventDefault();
151 | if(!disabledName)
152 | {
153 | createRoomButton.current.click();
154 | }
155 | }
156 | }}
157 | />
158 |
159 |
160 |
161 |
162 |
163 | {
178 | // it stores the details in localstorage which is used later
179 | localStorage.setItem('roomId',props.joinRoomId);
180 | localStorage.setItem('name',props.name);
181 | // isconnected is used to reconnect
182 | sessionStorage.setItem('isconnected',true);
183 | }}
184 | >
185 | Create Room
186 |
187 |
188 |
189 |
190 | }
195 | >
196 |
197 |
204 | Enter Your Name
205 |
206 | {
215 | props.setName(e.target.value);
216 | e.target.value.length >= 1
217 | ? setDisabledName(false)
218 | : setDisabledName(true);
219 | }}
220 | style={{ color: "#000" }}
221 | />
222 |
223 |
231 | Enter Room Id
232 |
233 | {
235 | props.setRoomID(event.target.value);
236 | validateRoomID(event.target.value)
237 | ? setDisabledRoomId(false)
238 | : setDisabledRoomId(true);
239 | }}
240 | onKeyPress={(ev) => {
241 | if(ev.key === 'Enter') {
242 | ev.preventDefault();
243 | if(!disabledName && !disabledRoomId)
244 | {
245 | joinRoomButton.current.click();
246 | }
247 | }
248 | }}
249 | fullWidth
250 | id="outlined-basic"
251 | className={classes.root}
252 | InputProps={{ className: classes.input }}
253 | label="Enter Room ID"
254 | variant="outlined"
255 | InputLabelProps={{
256 | shrink: true,
257 | }}
258 | placeholder="xxxx-yyyy-zzzz"
259 | />
260 |
261 |
262 |
263 |
264 |
265 | {
280 | // it stores the details in localstorage which are later used
281 | localStorage.setItem('roomId',props.joinRoomId)
282 | localStorage.setItem('name',props.name)
283 | sessionStorage.setItem('isconnected',true);
284 | }}
285 | >
286 | Join a Room
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 | );
298 | };
299 |
300 | Home.propTypes = {
301 | classes: PropTypes.object.isRequired,
302 | };
303 | const mapStateToProps = (state) => {
304 | return {
305 | joinRoomId: state.ROOM.roomId,
306 | name: state.ROOM.name,
307 | };
308 | };
309 |
310 | const mapDispatchToProps = (dispatch) => {
311 | return {
312 | setName: (name) => dispatch(actions.setName(name)),
313 | setRoomID: (ID) => dispatch(actions.setRoomID(ID)),
314 | reset: () => dispatch(actions.reset()),
315 | };
316 | };
317 |
318 | export default connect(
319 | mapStateToProps,
320 | mapDispatchToProps
321 | )(withStyles(styles)(Home));
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/Home/Home.module.css:
--------------------------------------------------------------------------------
1 | .home {
2 | font-family: "Poppins";
3 | background-color: #000a29;
4 | width: 100%;
5 | height: 100%;
6 | min-height: 100vh;
7 | padding: 47px 10px 11px 10px;
8 | }
9 |
10 | .home__svg {
11 | width: 85%;
12 | }
13 |
14 | .home__buttons {
15 | margin-top: 64%;
16 | margin-bottom: 82%;
17 | }
18 |
19 | .home__modal__container {
20 | padding: 25px;
21 | }
22 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/Loader/Loader.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import localclasses from "./Loader.module.css";
3 | import { XlviLoader } from "react-awesome-loaders";
4 | function Loader() {
5 | return (
6 |
7 |
12 |
13 | );
14 | }
15 | export default Loader;
16 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/Loader/Loader.module.css:
--------------------------------------------------------------------------------
1 | .load {
2 | background-color: #000a29;
3 | text-align: center;
4 | min-height: 100vh;
5 | display: flex;
6 | flex-direction: column;
7 | align-items: center;
8 | justify-content: center;
9 | }
10 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/Mobile/Mobile.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import bgimg from "../../images/mobilehome_svg.svg";
3 | import localclasses from "./Mobile.module.css";
4 |
5 | const Mobile = () => {
6 | return (
7 |
8 |
13 |
14 | )
15 | }
16 |
17 | export default Mobile
18 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/Mobile/Mobile.module.css:
--------------------------------------------------------------------------------
1 | .mobilehome__svg {
2 | height: 100%;
3 | width: 100%;
4 | }
5 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/Navbar/Navbar.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from "react";
2 | import AppBar from "@material-ui/core/AppBar";
3 | import {
4 | Toolbar,
5 | Typography,
6 | Button,
7 | Dialog,
8 | } from "@material-ui/core";
9 | import logo from "../../images/navlogo.png";
10 | import PersonIcon from "@material-ui/icons/Person";
11 | import SyntaxChat from "../SyntaxChat/SyntaxChat";
12 | import copy from "copy-to-clipboard";
13 | import About from "../About/About.js";
14 | import Slide from "@material-ui/core/Slide";
15 | import ParticpantsList from "../SyntaxChat/ParticipantsList";
16 | import { CallEnd } from "@material-ui/icons";
17 | import { Link } from "react-router-dom";
18 | import { connect } from "react-redux";
19 | import * as UIactions from "../../store/actions/uiActions.js";
20 |
21 | const Transition = React.forwardRef(function Transition(props, ref) {
22 | return ;
23 | });
24 |
25 | const Navbar = (props) => {
26 | const Copytext = (value) => {
27 | copy(value);
28 | props.setSnackBar("Room-ID Copied !","success");
29 | };
30 |
31 | const [open, setOpen] = React.useState(false);
32 |
33 | const handleClickOpen = () => {
34 | setOpen(true);
35 | };
36 | const handleClose = () => {
37 | setOpen(false);
38 | };
39 |
40 | return (
41 |
42 |
49 |
50 |
51 |
52 |
53 |
54 |
59 |
63 | SyntaxMeets
64 |
65 |
66 | }
69 | onClick={() => Copytext(`Hi there! You have been invited by ${props.name} to join SyntaxMeets. \n \nClick on this link - https://syntaxmeets.vercel.app \n \nand join the room by providing your name and Room-Id: ${props.roomId}`)}
70 | color="primary"
71 | style={{
72 | fontFamily: "poppins",
73 | marginLeft: "auto",
74 | fontWeight: "600",
75 | color: "white",
76 | }}
77 | >
78 |
86 | RoomId : {props.roomId}
87 |
88 |
89 |
94 |
95 |
106 | About Us
107 |
108 |
109 | }
112 | style={{
113 | fontFamily: "poppins",
114 | marginLeft: "15px",
115 | fontWeight: "600",
116 | color: "white",
117 | backgroundColor: "#fa1e0e",
118 | }}
119 | onClick={() => {
120 | props.socket.disconnect();
121 | }}
122 | >
123 | Leave
124 |
125 |
126 |
127 |
128 |
129 | );
130 | };
131 | // const mapStateToProps = (state) => {
132 | // return{
133 | // roomId:state.ROOM.roomId,
134 | // };
135 | // };
136 | const mapDispatchToProps = (dispatch) => {
137 | return {
138 | setSnackBar: (msg,type) => dispatch(UIactions.setSnackBar(msg,type)),
139 | };
140 | };
141 |
142 | export default connect(null, mapDispatchToProps)(Navbar);
143 |
144 |
145 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/SnackBar/Snackbar.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Snackbar from '@material-ui/core/Snackbar';
3 | import MuiAlert from '@material-ui/lab/Alert';
4 | import { connect } from 'react-redux';
5 | import { Typography } from '@material-ui/core';
6 |
7 | class SnackBar extends Component {
8 | handleClose = (e) => {
9 | this.props.close()
10 | }
11 | render() {
12 | return (
13 |
14 |
this.handleClose}>
15 | this.props.close()} severity={this.props.type}>
16 |
17 | {this.props.snackbarMessage}
18 |
19 |
20 |
21 |
22 | )
23 | }
24 | }
25 | function Alert(props) {
26 | return ;
27 | }
28 | const mapStateToProps = state => {
29 | return {
30 | isSnackOpen: state.UI.isSnackBarOpen,
31 | snackbarMessage: state.UI.setSnackBarMessage,
32 | type: state.UI.snackBarType
33 | }
34 | }
35 | const mapDispatchToProps = dispatch => {
36 | return { close: () => dispatch({ type: 'CLOSE_SNACKBAR' }) }
37 | }
38 | export default connect(mapStateToProps, mapDispatchToProps)(SnackBar)
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/SyntaxChat/ChatMessage.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import {
3 | ListItem,
4 | ListItemText,
5 | ListItemAvatar,
6 | Avatar,
7 | } from "@material-ui/core";
8 |
9 | const nameGenerator = (name) =>
10 | (name[0][0] + (name.length > 1 ? name[1][0] : "")).toUpperCase();
11 |
12 | export const ChatMessage = (props) => {
13 | return props.messages.map((data) => (
14 |
21 |
28 | {nameGenerator(data.name.split(" "))}
29 |
30 |
55 | {data.name}
56 |
57 | }
58 | secondary={
59 |
72 | {data.message}
73 |
74 | }
75 | />
76 |
77 | ));
78 | };
79 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/SyntaxChat/ParticipantsList.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import GroupIcon from "@material-ui/icons/Group";
3 | import {
4 | ListItem,
5 | ListItemText,
6 | ListItemAvatar,
7 | Avatar,
8 | Button,
9 | Drawer,
10 | List,
11 | } from "@material-ui/core";
12 | import { makeStyles } from "@material-ui/core/styles";
13 | import CloseSharpIcon from "@material-ui/icons/CloseSharp";
14 | import { connect } from "react-redux";
15 | const useStyles = makeStyles({
16 | list: {
17 | width: 400,
18 | },
19 | fullList: {
20 | width: "auto",
21 | },
22 | });
23 | const nameGenerator = name =>
24 | (name[0][0] + (name.length > 1 ? name[1][0] : "")).toUpperCase();
25 |
26 | function ParticipantsList(props) {
27 | const classes = useStyles();
28 | const { users } = props;
29 | const [openList, setOpenList] = useState(false);
30 |
31 | const renderParticipants = () => {
32 | return Object.keys(users).map(elem => {
33 | const name = users[elem];
34 | return (
35 | <>
36 |
37 |
38 |
39 | {nameGenerator(name.split(" "))}
40 |
41 |
42 |
57 |
58 | >
59 | );
60 | });
61 | };
62 | return (
63 |
64 |
setOpenList(true)}
66 | variant="contained"
67 | color="primary"
68 | startIcon={ }
69 | style={{
70 | fontFamily: "poppins",
71 | marginLeft: "15px",
72 | fontWeight: "600",
73 | color: "white",
74 | }}
75 | >
76 | Participants [ {Object.keys(users).length} ]
77 |
78 |
setOpenList(false)}
82 | >
83 | setOpenList(false)}
86 | />
87 |
96 | {renderParticipants()}
97 |
98 |
99 |
100 | );
101 | }
102 |
103 | const mapStateToProps = state => {
104 | return {
105 | users: state.ROOM.users,
106 | };
107 | };
108 |
109 | export default connect(mapStateToProps, null)(ParticipantsList);
110 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/SyntaxChat/SyntaxChat.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useRef } from "react";
2 | import { makeStyles } from "@material-ui/core/styles";
3 | import InsertEmoticonIcon from "@material-ui/icons/InsertEmoticon";
4 | import {
5 | Drawer,
6 | Button,
7 | Divider,
8 | TextField,
9 | Grid,
10 | Typography
11 | } from "@material-ui/core";
12 | import { connect } from "react-redux";
13 | import * as actions from "../../store/actions/chatActions.js";
14 | import * as UIactions from "../../store/actions/uiActions.js";
15 | import SendIcon from "@material-ui/icons/Send";
16 | import ForumIcon from "@material-ui/icons/Forum";
17 | import { ChatMessage } from "./ChatMessage";
18 | import CloseSharpIcon from "@material-ui/icons/CloseSharp";
19 | import "emoji-mart/css/emoji-mart.css";
20 | import { Picker } from "emoji-mart";
21 |
22 | const useStyles = makeStyles({
23 | list: {
24 | width: 400
25 | },
26 | fullList: {
27 | width: "auto"
28 | }
29 | });
30 |
31 | const SyntaxChat = (props) => {
32 | const classes = useStyles();
33 | const [emojiPickerState, SetEmojiPicker] = useState(false);
34 | const messagesEndRef = useRef(null);
35 | const [openDrawer, setopenDrawer] = useState(false);
36 |
37 | const handleMessageSubmit = () => {
38 | // this if block is called when page is reloaded
39 | // it ensures that user is connected back to same room to incorporate smooth chating
40 | if (localStorage.getItem("flag") && sessionStorage.getItem("isconnected")) {
41 | if (props.message.trim() === "") return;
42 | SetEmojiPicker(false);
43 | // this data extract info from localStorage
44 | let data = {
45 | name: localStorage.getItem("name"),
46 | roomId: localStorage.getItem("roomId"),
47 | message: props.message
48 | };
49 | // this is used to connect back the user
50 | props.socket.emit("chatmessage", data);
51 | props.setMessages(data);
52 | props.setMessage("");
53 | }
54 | // this block is called when the user connects first time
55 | else {
56 | if (props.message.trim() === "") return;
57 | SetEmojiPicker(false);
58 | let data = {
59 | name: props.name,
60 | roomId: props.roomId,
61 | message: props.message
62 | };
63 | props.socket.emit("chatmessage", data);
64 |
65 | props.setMessages(data);
66 | props.setMessage("");
67 | }
68 | };
69 |
70 | useEffect(() => {
71 | props.socket.on("chatmessage", (data) => {
72 | props.setMessages(data);
73 | });
74 | let timeout;
75 | // recieve the user who is currently typing's data from the backend
76 | props.socket.on("typing", (data) => {
77 | props.whoIsTyping(data.name);
78 | //Remove the timeout(to clear typing message) , if someone has again typed something
79 | clearTimeout(timeout);
80 | timeout = setTimeout(() => {
81 | //Remove the typing message if no one is typing after 500ms
82 | props.whoIsTyping();
83 | }, 500);
84 | });
85 | }, []);
86 |
87 | useEffect(()=> {
88 | let lastMessage = props.messages[props.messages.length - 1];
89 | if (props.name && lastMessage) {
90 | if (props.name !== lastMessage.name) {
91 | console.log("NEW MESSAGE");
92 | lastMessage.message.length > 20 ? props.setSnackBar(`${lastMessage.name}: ${lastMessage.message.substring(0,20)}...`, "warning") : props.setSnackBar(`${lastMessage.name}: ${lastMessage.message}`, "warning")
93 | }
94 | }
95 | }, [props.messages]);
96 |
97 | const scrollToBottom = () => {
98 | if (messagesEndRef.current) {
99 | messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
100 | }
101 | };
102 |
103 | function triggerPicker(event) {
104 | event.preventDefault();
105 | SetEmojiPicker(!emojiPickerState);
106 | }
107 | useEffect(scrollToBottom, [props.messages]);
108 | let emojiPicker;
109 | if (emojiPickerState) {
110 | emojiPicker = (
111 | props.setMessage(props.message + emoji.native)}
115 | // style={{width: "90%", display: "flex"}}
116 | />
117 | );
118 | }
119 |
120 | const toggleDrawer = (open) => (event) => {
121 | if (
122 | event.type === "keydown" &&
123 | (event.key === "Tab" || event.key === "Shift")
124 | ) {
125 | return;
126 | }
127 | setopenDrawer(open);
128 | };
129 |
130 | return (
131 |
132 |
}
136 | color="primary"
137 | style={{
138 | fontFamily: "poppins",
139 | marginLeft: "15px",
140 | fontWeight: "600",
141 | color: "white"
142 | }}
143 | >
144 | Chat Box
145 |
146 |
147 |
151 |
156 |
166 |
175 |
176 |
177 |
178 |
179 |
180 | {props.typingUser ? (
181 |
182 |
183 |
191 | {props.typingUser} is typing...
192 |
193 |
194 |
195 |
196 | ) : undefined}
197 |
198 |
199 | {/* */}
200 |
201 | {/* */}
209 |
210 |
223 | {/* */}
224 |
225 |
226 |
227 | {
235 | props.socket.emit("typing", {
236 | id: props.socket.id,
237 | name: props.name
238 | });
239 | props.setMessage(e.target.value);
240 | }}
241 | onKeyDown={(e) => {
242 | if (e.key === "Enter") {
243 | handleMessageSubmit();
244 | }
245 | }}
246 | />
247 | {/* SetMessage(event.target.value)}
254 | /> */}
255 |
256 |
257 | }
269 | onClick={handleMessageSubmit}
270 | >
271 | Send
272 |
273 |
274 |
275 |
276 |
277 |
278 | {emojiPicker}
279 |
280 |
281 |
282 |
283 |
284 |
285 | );
286 | };
287 |
288 | const mapStateToProps = (state) => {
289 | return {
290 | typingUser: state.CHAT.typingUser,
291 | message: state.CHAT.message,
292 | messages: state.CHAT.chat
293 | };
294 | };
295 |
296 | const mapDispatchToProps = (dispatch) => {
297 | return {
298 | setSnackBar: (msg,type) => dispatch(UIactions.setSnackBar(msg,type)),
299 | setMessage: (msg) => dispatch(actions.setMessage(msg)),
300 | setMessages: (msg) => dispatch(actions.makeMessage(msg)),
301 | whoIsTyping: (user) => dispatch(actions.whoIsTyping(user))
302 | };
303 | };
304 | export default connect(mapStateToProps, mapDispatchToProps)(SyntaxChat);
305 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/SyntaxEditor/CodeInput.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import AceEditor from "react-ace";
3 | import { connect } from "react-redux";
4 | import * as actions from "../../store/actions/editorActions.js";
5 | const INPUT = (props) => {
6 | const handleIChange = (newValue) => {
7 | props.setCodeInput(newValue);
8 | };
9 |
10 | return (
11 |
20 | );
21 | };
22 |
23 | const mapStateToProps = (state) => {
24 | return {
25 | codeInput: state.EDITOR.codeInput,
26 | };
27 | };
28 |
29 | const mapDispatchToProps = (dispatch) => {
30 | return {
31 | setCodeInput: (input) => dispatch(actions.setCodeInput(input)),
32 | };
33 | };
34 |
35 | export default connect(mapStateToProps,mapDispatchToProps)(INPUT);
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/SyntaxEditor/CodeOutput.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import AceEditor from "react-ace";
3 | import { connect } from "react-redux";
4 |
5 | const OUTPUT = (props) => {
6 |
7 | return (
8 |
24 | );
25 | };
26 |
27 |
28 | const mapStateToProps = (state) => {
29 | return {
30 | codeOutput: state.EDITOR.codeOutput,
31 | };
32 | };
33 | export default connect(mapStateToProps)(OUTPUT);
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/SyntaxEditor/LanguageData.js:
--------------------------------------------------------------------------------
1 | export const languages = [
2 |
3 | "c_cpp",
4 | "clojure",
5 | "csharp",
6 | "cobol",
7 | "erlang",
8 | "fortran",
9 | "golang",
10 | "groovy",
11 | "java",
12 | "javascript",
13 | "kotlin",
14 | "php",
15 | "python",
16 | "r",
17 | "ruby",
18 | "sql",
19 | "swift",
20 | "typescript",
21 | ];
22 |
23 |
24 | export const defaultValue = `#include
25 | #define lli long long int
26 | #define endl "\\n"
27 | #define MAX 1000005
28 | #define MOD 1000000007
29 | using namespace std;
30 | int main()
31 | {
32 | int t;
33 | cin>>t;
34 |
35 | while(t--)
36 | {
37 | //your code
38 |
39 | }
40 | return 0;
41 | }`;
42 |
43 | export const langExtensionDict = {
44 | ".c": "C",
45 | ".cpp": "C++",
46 | ".java": "JAVA",
47 | ".js": "JavaScript",
48 | ".ts": "TypeScript",
49 | ".clj": "Closure",
50 | ".cljs": "Closure",
51 | ".cs": "C#",
52 | ".cbl": "COBOL",
53 | ".cob": "COBOL",
54 | ".cpy": "COBOL",
55 | ".erl": "Erlang",
56 | ".hrl": "Erlang",
57 | ".go": "Go",
58 | ".py": "Python",
59 | ".f90": "FortRan",
60 | ".f95": "FortRan",
61 | ".f03": "FortRan",
62 | ".txt": "",
63 | ".groovy": "Groovy",
64 | ".gvy": "Groovy",
65 | ".gy": "Groovy",
66 | ".gshgsh": "Groovy",
67 | ".kt": "Kotlin",
68 | ".kts": "Kotlin",
69 | ".ktm": "Kotlin",
70 | ".php": "PHP",
71 | ".r": "R",
72 | ".rb": "Ruby",
73 | ".sql": "SQL",
74 | ".swift": "Swift"
75 | };
76 |
77 | export const LangOptions = [
78 | "C" ,
79 | "C++" ,
80 | "Python",
81 | "JAVA",
82 | "JavaScript",
83 | "Kotlin",
84 | "Clojure" ,
85 | "C#",
86 | "COBOL",
87 | "Erlang",
88 | "FortRan",
89 | "Go",
90 | "Groovy",
91 | "PHP",
92 | "R",
93 | "Ruby",
94 | "SQL",
95 | "Swift",
96 | "TypeScript"
97 | ]
98 |
99 | export const langId = {
100 |
101 | "C" : 50,
102 | "C++" : 54,
103 | "Clojure" : 86,
104 | "C#": 51,
105 | "COBOL": 77,
106 | "Erlang": 58,
107 | "FortRan": 59,
108 | "Go": 60,
109 | "Groovy": 88,
110 | "JAVA": 62,
111 | "JavaScript": 63,
112 | "Kotlin": 78,
113 | "PHP": 68,
114 | "Python": 71,
115 | "R": 80,
116 | "Ruby": 72,
117 | "SQL": 82,
118 | "Swift": 83,
119 | "TypeScript": 74
120 |
121 | }
122 |
123 | export const langMode = {
124 |
125 | "C": "c_cpp",
126 | "C++": "c_cpp",
127 | "Clojure": "clojure",
128 | "C#": "csharp",
129 | "COBOL": "cobol",
130 | "Erlang": "erlang",
131 | "FortRan": "fortran",
132 | "Go": "golang",
133 | "Groovy": "groovy",
134 | "JAVA": "java",
135 | "JavaScript": "javascript",
136 | "Kotlin": "kotlin",
137 | "PHP": "php",
138 | "Python": "python",
139 | "R": "r",
140 | "Ruby": "ruby",
141 | "SQL": "sql",
142 | "Swift": "swift",
143 | "TypeScript": "typescript",
144 |
145 | }
146 |
147 |
148 | export const themes = [
149 | "monokai",
150 | "github",
151 | "tomorrow_night",
152 | "tomorrow",
153 | "kuroir",
154 | "twilight",
155 | "xcode",
156 | "textmate",
157 | "solarized_dark",
158 | "solarized_light",
159 | "terminal",
160 | ];
161 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/SyntaxEditor/SyntaxEditor.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment, useEffect, useState } from "react";
2 | import AceEditor from "react-ace";
3 | import "ace-builds/src-min-noconflict/ext-searchbox";
4 | import "ace-builds/src-min-noconflict/ext-language_tools";
5 | import "ace-builds/src-noconflict/mode-jsx";
6 | import {
7 | AppBar,
8 | FormControl,
9 | InputLabel,
10 | makeStyles,
11 | MenuItem,
12 | Select,
13 | Toolbar,
14 | Typography,
15 | FormControlLabel,
16 | Switch,
17 | Button,
18 | Dialog,
19 | DialogTitle,
20 | DialogActions,
21 | Snackbar,
22 | ButtonGroup,
23 | Tooltip,
24 | Zoom,
25 | DialogContent,
26 | } from "@material-ui/core";
27 | import Grid from "@material-ui/core/Grid";
28 | import Alert from "@material-ui/lab/Alert";
29 | import localClasses from "./SyntaxEditor.module.css";
30 | import {
31 | languages,
32 | langMode,
33 | LangOptions,
34 | langId,
35 | langExtensionDict,
36 | themes,
37 | } from "./LanguageData";
38 | import Modal from "react-modal";
39 | import ShareIcon from "@material-ui/icons/Share";
40 | import PlayArrowIcon from "@material-ui/icons/PlayArrow";
41 | import FileCopyIcon from "@material-ui/icons/FileCopy";
42 | import CloudUploadIcon from "@material-ui/icons/CloudUpload";
43 | import INPUT from "./CodeInput";
44 | import OUTPUT from "./CodeOutput";
45 | import copy from "copy-to-clipboard";
46 | import { connect } from "react-redux";
47 | import * as actions from "../../store/actions/editorActions.js";
48 | import CloudDownloadRounded from "@material-ui/icons/CloudDownloadRounded";
49 | import FullscreenRounded from "@material-ui/icons/FullscreenRounded";
50 | import FullscreenExitRounded from "@material-ui/icons/FullscreenExitRounded";
51 | import CloseIcon from '@material-ui/icons/Close';
52 | import { getExtensionByLangCode } from "../../util/util";
53 | import { css } from "@emotion/react";
54 | import BeatLoader from "react-spinners/BeatLoader";
55 |
56 | //extracting all the languages recquired
57 | languages.forEach((lang) => {
58 | require(`ace-builds/src-noconflict/mode-${lang}`);
59 | require(`ace-builds/src-noconflict/snippets/${lang}`);
60 | });
61 |
62 |
63 | // Can be a string as well. Need to ensure each key-value pair ends with ;
64 | const override = css`
65 | display: block;
66 | margin: 0 auto;
67 | border-color: red;
68 | `;
69 | //extracting themes
70 | themes.forEach((theme) => require(`ace-builds/src-noconflict/theme-${theme}`));
71 |
72 | const useStyles = makeStyles((mutheme) => ({
73 | formControl: {
74 | margin: mutheme.spacing(1),
75 | minWidth: 120,
76 | },
77 | selectEmpty: {
78 | marginTop: mutheme.spacing(2),
79 | },
80 | }));
81 |
82 | Modal.setAppElement('#root')
83 |
84 | const SyntaxEditor = (props) => {
85 | const [theme, setTheme] = useState("monokai");
86 | const [popup, setPopup] = useState([false, ""]);
87 | const [filePopup, setFilePopup] = useState(false);
88 | const [fileHandleError, setFileHandleError] = useState("");
89 | const [fullscreen,setFullscreen] = useState(false); // maintain state of screen in syntax Editor
90 | const [modalIsOpen,setModalIsOpen] = useState(false)
91 | const [shareURL,setshareURL] = useState("")
92 | const [isLoading,setIsLoading]=useState(false)
93 |
94 | // This will resend a message to update the code of the newly joined user
95 | useEffect(() => {
96 | let UpdatedCode = props.code;
97 | if (props.previousUser.id === props.id) {
98 | props.socket.emit("message", UpdatedCode);
99 | }
100 | // if the user was connected then over reloading the page this block is called
101 | else if(sessionStorage.getItem('isconnected'))
102 | {
103 | //it used to save the code in sessionStorage when only one user is using there in a room
104 | props.setCode(sessionStorage.getItem('code'));
105 | }
106 | }, [props.previousUser]);
107 |
108 | const classes = useStyles();
109 | useEffect(() => {
110 | props.socket.on("message", (newValue) => {
111 | props.setCode(newValue);
112 | });
113 | }, []);
114 |
115 | const handleChange = (newValue) => {
116 | props.setCode(newValue);
117 | sessionStorage.setItem('code',newValue);
118 | props.socket.emit("message", newValue);
119 | };
120 |
121 | const copyCode = (value) => {
122 | copy(value);
123 | setPopup([true, "Code Copied Sucessfully"]);
124 | };
125 |
126 | const fetchSharedCodeLink=async (content) =>{
127 | var response = await fetch("https://dpaste.com/api/v2/", {
128 | method: "POST",
129 | headers: { "Content-Type": "application/x-www-form-urlencoded" },
130 | body: "content=" + encodeURIComponent(content)
131 | });
132 | return response.text();
133 | }
134 |
135 | const shareCode = (value) => {
136 | setModalIsOpen(true)
137 | setIsLoading(true)
138 | fetchSharedCodeLink(value).then(url => {setIsLoading(false);setshareURL(url) });
139 | }
140 |
141 | const handleCodeRun = () => {
142 | props.executeCode(langId[props.currLang], props.code, props.codeInput);
143 | };
144 |
145 | const handleCodeDownload = () => {
146 | // download code here...
147 | const element = document.createElement("a");
148 | const file = new Blob([props.code], {
149 | type: "text/plain;charset=utf-8",
150 | });
151 | element.href = URL.createObjectURL(file);
152 | element.download = `syntaxmeets-code.${getExtensionByLangCode(
153 | props.currLang
154 | )}`;
155 | document.body.appendChild(element);
156 | element.click();
157 | };
158 |
159 | const IONavbar = (props) => {
160 | return (
161 |
162 |
175 | {props.type}
176 |
177 |
178 | );
179 | };
180 |
181 | const uploadFile = () => {
182 | document.querySelector("#upload").click();
183 | };
184 |
185 | const checkValidFileExtension = (file) => {
186 | const validExtensions = Object.keys(langExtensionDict);
187 | var name = file.name;
188 | var valid = false;
189 | if (name.length > 0) {
190 | for (var i = 0; i < validExtensions.length; ++i) {
191 | var ext = validExtensions[i];
192 | if (
193 | name.substr(name.length - ext.length, ext.length).toLowerCase() ==
194 | ext.toLowerCase()
195 | ) {
196 | valid = true;
197 | break;
198 | }
199 | }
200 | }
201 | return valid;
202 | };
203 |
204 | const handleFileChange = () => {
205 | var file = document.querySelector("#upload").files[0];
206 |
207 | if (file) {
208 | var reader = new FileReader();
209 |
210 | reader.onload = function (e) {
211 | if (file.size > 10000) {
212 | setFilePopup(true);
213 | setFileHandleError("Error: File size greater than 10KB!");
214 | return;
215 | }
216 |
217 | if (!checkValidFileExtension(file)) {
218 | setFilePopup(true);
219 | setFileHandleError("Error: Not a Valid File Extension!");
220 | return;
221 | }
222 |
223 | handleChange(e.target.result);
224 | const fileNameArr = file.name.split(".");
225 | const ext = `.${fileNameArr[fileNameArr.length - 1]}`;
226 | props.setLanguage(langExtensionDict[ext]);
227 | };
228 |
229 | reader.onerror = function (e) {
230 | console.error("An error ocurred reading the file", e);
231 | };
232 |
233 | reader.readAsText(file, "UTF-8");
234 | }
235 | };
236 |
237 | // handle fullscreen mode
238 | const handleFullscreen = (props) =>{
239 | fullscreen ? setFullscreen(false) : setFullscreen(true);
240 | props.toggleFocusMode();
241 | }
242 |
243 | return (
244 |
245 |
246 | Compiling ...
247 |
248 |
249 |
250 |
251 |
252 | >
253 |
254 |
255 |
256 |
257 | Oops Error Occured
258 | {props.codeError}
259 |
260 | props.setIsError(false)}
262 | variant="contained"
263 | size="large"
264 | color="primary"
265 | >
266 | Close
267 |
268 |
269 |
270 | {
274 | setPopup([false, ""]);
275 | }}
276 | >
277 | {
279 | setPopup([false, ""]);
280 | }}
281 | severity="success"
282 | variant="filled"
283 | >
284 | {popup[1]}
285 |
286 |
287 | {
291 | setFilePopup(false);
292 | }}
293 | >
294 | {
296 | setFilePopup(false);
297 | }}
298 | severity="error"
299 | variant="filled"
300 | >
301 | {fileHandleError}
302 |
303 |
304 |
305 |
306 |
318 | SyntaxEditor
319 |
320 |
321 |
326 |
330 | Language
331 |
332 | {
338 | props.setLanguage(e.target.value);
339 | }}
340 | label="Language"
341 | style={{ fontFamily: "poppins", color: "#ffffff" }}
342 | >
343 | {LangOptions.map((language) => (
344 |
345 |
346 | {language}
347 |
348 |
349 | ))}
350 |
351 |
352 |
357 |
361 | Theme
362 |
363 | setTheme(e.target.value)}
368 | value={theme}
369 | label="Theme"
370 | style={{ fontFamily: "poppins", color: "#ffffff" }}
371 | >
372 | {themes.map((lang) => (
373 |
374 | {lang}
375 |
376 | ))}
377 |
378 |
379 |
384 |
388 | Font Size
389 |
390 | props.setFontSize(e.target.value)}
395 | value={props.fontSize}
396 | label="Font Size"
397 | style={{ fontFamily: "poppins", color: "#ffffff" }}
398 | >
399 | {[10, 12, 14, 16, 18, 20, 24, 28, 32, 40].map((size) => (
400 |
401 | {size}
402 |
403 | ))}
404 |
405 |
406 |
407 |
408 |
409 |
410 | {
411 | setModalIsOpen(false)
412 | setshareURL("")
413 | }}/>
414 |
415 | Share Your Code
416 |
417 |
418 |
419 | {isLoading ?
420 | :
421 | <>
422 | {shareURL}
423 |
424 | {
428 | copy(shareURL)
429 | setPopup([true, "Url Copied !!!"])
430 | }}
431 | style={{
432 | fontFamily: "poppins",
433 | marginLeft: "auto",
434 | fontWeight: "600",
435 | color: "white",
436 | }}
437 | >
438 |
439 |
440 |
441 | >
442 | }
443 |
444 |
445 |
446 |
463 |
467 |
468 | {
474 | props.setAutoCompletion(!props.autoCompletion);
475 | }}
476 | name="EnableAutoCompletion"
477 | />
478 | }
479 | label={
480 |
481 | Auto-complete
482 |
483 | }
484 | />
485 | handleFileChange()}
489 | hidden
490 | accept=".c, .cpp, .java, .js, .ts, .clj, .cljs, .cs, .cbl, .cob, .cpy, .erl, .hrl, .go, .py, .f90, .f95, .f03, .txt, .groovy, .gvy, .gy, .gsh, .kt, .kts, .ktm, .php, .r, .rb, .sql, .swift"
491 | />
492 |
497 |
498 | uploadFile()}
502 | style={{
503 | fontFamily: "poppins",
504 | marginLeft: "auto",
505 | fontWeight: "600",
506 | color: "white",
507 | }}
508 | >
509 |
510 |
511 |
512 |
513 | shareCode(props.code)}
517 | style={{
518 | fontFamily: "poppins",
519 | marginLeft: "auto",
520 | fontWeight: "600",
521 | color: "white",
522 | }}
523 | >
524 |
525 |
526 |
527 |
528 | copyCode(props.code)}
532 | style={{
533 | fontFamily: "poppins",
534 | marginLeft: "auto",
535 | fontWeight: "600",
536 | color: "white",
537 | }}
538 | >
539 |
540 |
541 |
542 |
543 |
554 |
555 |
556 |
557 |
558 | handleFullscreen(props)}
568 | >
569 | {fullscreen
570 | ?
571 | :
572 | }
573 |
574 |
575 |
576 | }
581 | style={{
582 | fontFamily: "poppins",
583 | marginLeft: "10px",
584 | fontWeight: "600",
585 | color: "#fff",
586 | backgroundColor: "#FFD500",
587 | }}
588 | >
589 | Run
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 | );
606 | };
607 |
608 | const mapStateToProps = (state) => {
609 | return {
610 | code: state.EDITOR.code,
611 | currLang: state.EDITOR.lang,
612 | fontSize: state.EDITOR.fontSize,
613 | autoCompletion: state.EDITOR.autoCompletion,
614 | codeInput: state.EDITOR.codeInput,
615 | codeOutput: state.EDITOR.codeOutput,
616 | isCompiling: state.EDITOR.isCompiling,
617 | isError: state.EDITOR.isError,
618 | codeError: state.EDITOR.codeError,
619 | previousUser: state.ROOM.previousUser,
620 | id: state.ROOM.id,
621 | };
622 | };
623 |
624 | const mapDispatchToProps = (dispatch) => {
625 | return {
626 | setCode: (code) => dispatch(actions.setCode(code)),
627 | setLanguage: (lang) => dispatch(actions.setLanguage(lang)),
628 | setFontSize: (size) => dispatch(actions.setFontSize(size)),
629 | setAutoCompletion: (name) => dispatch(actions.setAutoCompletion(name)),
630 | setIsError: (isactive) => dispatch(actions.setIsError(isactive)),
631 | executeCode: (langId, code, input) =>
632 | dispatch(actions.executeCode(langId, code, input)),
633 | toggleFocusMode: () => dispatch(actions.toggleFocusMode()),
634 | };
635 | };
636 | export default connect(mapStateToProps, mapDispatchToProps)(SyntaxEditor);
637 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/SyntaxEditor/SyntaxEditor.module.css:
--------------------------------------------------------------------------------
1 | .Editor__navbar {
2 | display: flex;
3 | flex-direction: row;
4 | justify-content: space-between;
5 | padding: auto 5px;
6 | }
7 |
8 | .Menu__options {
9 | font-family: "poppins";
10 | font-size: 13px;
11 | }
12 |
13 | .loader {
14 | color: #ffd500;
15 | background-color: #000a29;
16 | font-family: Consolas, Menlo, Monaco, monospace;
17 | font-weight: bold;
18 | font-size: 30vh;
19 | opacity: 1;
20 | }
21 | .loader span {
22 | display: inline-block;
23 | animation: pulse 0.4s alternate infinite ease-in-out;
24 | }
25 | .loader span:nth-child(odd) {
26 | animation-delay: 0.4s;
27 | }
28 | .arrow {
29 | font-size: 200px;
30 | }
31 | @keyframes pulse {
32 | to {
33 | transform: scale(0.8);
34 | opacity: 0.5;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/SyntaxPad/SyntaxPad.js:
--------------------------------------------------------------------------------
1 | import React, {Fragment ,useRef,useState} from "react";
2 | import { AppBar, Toolbar, Typography, Button } from "@material-ui/core";
3 | import CanvasDraw from "react-canvas-draw";
4 | import UndoIcon from "@material-ui/icons/Undo";
5 | import DeleteIcon from "@material-ui/icons/Delete";
6 | import localClasses from "./SyntaxPad.module.css";
7 | import { ChromePicker } from 'react-color';
8 | import ColorLensIcon from '@material-ui/icons/ColorLens';
9 |
10 | const SyntaxPad = (props) => {
11 |
12 | const saveableCanvas = useRef(CanvasDraw);
13 | const [displayColorPicker, setdisplayColorPicker] = useState(false)
14 | const [brushColor, setBrushColor] = useState("#000A29")
15 |
16 | const popover = {
17 | position: 'absolute',
18 | zIndex: '100',
19 | left: '-50px'
20 | }
21 | const cover = {
22 | position: 'fixed',
23 | top: '0px',
24 | right: '0px',
25 | bottom: '0px',
26 | left: '0px',
27 | }
28 |
29 | const handleColorOpen = () =>{
30 | setdisplayColorPicker(true);
31 | }
32 |
33 | const handleColorClose = () =>{
34 | setdisplayColorPicker(false);
35 | }
36 |
37 | const handleColorChange = (color) => {
38 | setBrushColor(color.hex);
39 | }
40 |
41 | return (
42 |
43 |
44 |
45 |
49 | SyntaxPad
50 |
51 |
52 |
53 |
}
58 | style={{
59 | fontFamily: "poppins",
60 | marginLeft: "auto",
61 | fontWeight: "600",
62 | color: "white",
63 | }}
64 | >
65 | Pick Color
66 |
67 | { displayColorPicker ?
: null }
71 |
72 |
73 |
74 |
75 |
76 |
85 |
86 |
87 |
88 | {
92 | saveableCanvas.current.clear();
93 | }}
94 | startIcon={ }
95 | style={{
96 | fontFamily: "poppins",
97 | marginLeft: "auto",
98 | fontWeight: "600",
99 | color: "white",
100 |
101 | }}
102 | >
103 | Clear
104 |
105 | }
108 | style={{
109 | fontFamily: "poppins",
110 | marginLeft: "15px",
111 | fontWeight: "600",
112 | color: "white",
113 | backgroundColor: "#FFD500",
114 | }}
115 | onClick={() => {
116 | saveableCanvas.current.undo();
117 | }}
118 | >
119 | UNDO
120 |
121 |
122 |
123 |
124 | );
125 |
126 | }
127 |
128 | export default SyntaxPad;
129 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/SyntaxPad/SyntaxPad.module.css:
--------------------------------------------------------------------------------
1 | .Editor__navbar {
2 | display: flex;
3 | flex-direction: row;
4 | justify-content: space-between;
5 | padding: auto 5px;
6 | }
7 |
8 | .Menu__options {
9 | font-family: "poppins";
10 | font-size: 13px;
11 | color: white;
12 | }
13 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/components/SyntaxRoom/SyntaxRoom.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment, useEffect, useState } from "react";
2 | import Navbar from "../Navbar/Navbar";
3 | import {
4 | Button,
5 | Dialog,
6 | DialogActions,
7 | DialogTitle,
8 | Grid,
9 | } from "@material-ui/core";
10 | import SyntaxEditor from "../SyntaxEditor/SyntaxEditor";
11 | import SyntaxPad from "../SyntaxPad/SyntaxPad";
12 | import { Redirect } from "react-router-dom";
13 | import Footer from "../Footer/Footer";
14 | import { socket } from "../../services/socket";
15 | import { validateRoomID } from "../../util/util";
16 | import { connect } from "react-redux";
17 | import * as actions from "../../store/actions/roomActions.js";
18 | import * as UIactions from "../../store/actions/uiActions.js";
19 |
20 |
21 | // use following in case of localhost
22 | //import io from "socket.io-client";
23 | // to use for localhost
24 | //var socket = io.connect("http://localhost:4000");
25 |
26 | const SyntaxRoom = (props) => {
27 | const [popup, setPopup] = useState(false);
28 | const [popupMessage, setPopupMessage] = useState("");
29 |
30 | const roomId = props.roomId;
31 | useEffect(() => {
32 | // If disconnected then connect again to server
33 | // Trigerred when user leaves a room
34 | socket.on("disconnect", (reason) => {
35 | props.reset();
36 | socket.connect();
37 | });
38 |
39 | });
40 | useEffect(() => {
41 | // fetch the list of active rooms from backend
42 | var roomsList = [];
43 | // all active roomids are there in backend/rooms
44 | const url = `${process.env.REACT_APP_SYNTAXMEETS_BACKEND_API}/rooms`;
45 | // this fetch function fetches the list of active list
46 | fetch(url)
47 | .then(res => {
48 | return res.json();
49 | })
50 | .then(rooms => {
51 | console.log(rooms);
52 | for (let i = 0; i < rooms.length; i++)
53 | roomsList.push(rooms[i]);
54 | });
55 | // roomid gets the roomId from local storage
56 | var roomid = localStorage.getItem('roomId');
57 |
58 | if (props.Username === undefined || props.Username === "") {
59 | setPopup(true);
60 | setPopupMessage("Name not found");
61 | }
62 |
63 |
64 | if (props.location.name === undefined || props.location.name === "") {
65 | // If user disconnects and want to connect back to same room
66 | // flag is used to check whether roomid is active or not
67 | var flag = false;
68 | flag = roomsList.includes(roomid);
69 | localStorage.setItem('flag', flag);
70 | // this if statement is called when reload of page takes places
71 | // it just joins the user back to same roomId using socket
72 | if (localStorage.getItem('flag') && sessionStorage.getItem('isconnected')) {
73 | props.location.name = localStorage.getItem('name');
74 | let data = {
75 | room: localStorage.getItem('roomId'),
76 | name: localStorage.getItem('name'),
77 | }
78 | // join back to same room
79 | socket.emit("joinroom", data);
80 | }
81 | else {
82 | // direct back to home
83 | alert("Please Enter your name");
84 | props.reset();
85 | props.setGoToHome(true);
86 | }
87 | }
88 |
89 | if (validateRoomID(roomId) === false || props.location.pathname === "") {
90 | setPopup(true);
91 | setPopupMessage("Invalid Room Id");
92 | }
93 | // this will send server(backend) the roomId in which the props.socket needs to be joined
94 | //this code will run only once
95 | let data = {
96 | room: roomId,
97 | name: props.Username,
98 | };
99 | socket.emit("joinroom", data);
100 | localStorage.setItem("my_name", props.Username);
101 | socket.on("addusers", (data) => {
102 | // When a new User joins in the room
103 | // Get all the users from the backend , when the current user joins in the room
104 | // so fetch all users from backend and store in the frontend
105 | // Also pass id of current user from backend
106 | props.setUsers(data.users);
107 | let msg = data.users[data.id] + " , Welcome to Syntax Meets!";
108 | props.setSnackBar(msg, "success");
109 | props.setId(data.id);
110 | });
111 | socket.on("userjoined", (users) => {
112 | // For all other users (excluding the new user) , just get the new user data who entered the room
113 | // and a old user who will emit the code to be updated for new user
114 | // so update in the state
115 | const { newUser, oldUser } = users;
116 | const id = Object.keys(newUser)[0];
117 | props.setUsers(newUser);
118 | let msg = newUser[id] + " , Welcome to Syntax Meets!";
119 | props.setSnackBar(msg, "success");
120 | props.setPreviousUser({ id: Object.keys(oldUser)[0] });
121 | });
122 |
123 | socket.on("userleft", (userObject) => {
124 | props.removeUser(userObject);
125 | let msg = userObject.name + " Left the Room.";
126 | props.setSnackBar(msg, "error");
127 | });
128 | }, []);
129 |
130 | return (
131 |
132 | {props.goToHome ? (
133 |
134 | ) : (
135 |
136 |
137 |
138 | {popupMessage}
139 |
140 |
141 | {
143 | setPopup(false);
144 | setPopupMessage("");
145 | props.reset();
146 | props.setGoToHome(true);
147 | }}
148 | variant="contained"
149 | size="large"
150 | style={{ backgroundColor: "#f57c00" }}
151 | >
152 | OK
153 |
154 |
155 |
156 |
157 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 | )}
175 |
176 |
177 | );
178 | };
179 | const mapStateToProps = (state) => {
180 | return {
181 | users: state.ROOM.users,
182 | roomId: state.ROOM.roomId,
183 | id: state.ROOM.id, // Stores the userid default 1 and then increases and decreases according to the users.
184 | Username: state.ROOM.name,
185 | previousUser: state.ROOM.previousUser, //Store the id of an already existing user , so this user will emit the code when a new user joins
186 | goToHome: state.ROOM.goToHome,
187 | isFocusMode: state.UI.isFocusMode,
188 | };
189 | };
190 |
191 | const mapDispatchToProps = (dispatch) => {
192 | return {
193 | setUsers: (users) => dispatch(actions.setUsers(users)),
194 | setName: (name) => dispatch(actions.setName(name)),
195 | setId: (id) => dispatch(actions.setId(id)),
196 | setPreviousUser: (user) => dispatch(actions.setPreviousUser(user)),
197 | setGoToHome: (isvalid) => dispatch(actions.setGoToHome(isvalid)),
198 | removeUser: (name) => dispatch(actions.removeUser(name)),
199 | reset: () => dispatch(actions.reset()),
200 | setSnackBar: (msg, type) => dispatch(UIactions.setSnackBar(msg, type)),
201 | };
202 | };
203 |
204 |
205 | export default connect(mapStateToProps, mapDispatchToProps)(SyntaxRoom);
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/images/SyntaxMeets.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kothariji/SyntaxMeets/74f10e80ae3e42908f9943e27ca06e99a0d53530/frontend/syntaxmeets/src/images/SyntaxMeets.png
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/images/akash.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kothariji/SyntaxMeets/74f10e80ae3e42908f9943e27ca06e99a0d53530/frontend/syntaxmeets/src/images/akash.jpg
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/images/dhruv.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kothariji/SyntaxMeets/74f10e80ae3e42908f9943e27ca06e99a0d53530/frontend/syntaxmeets/src/images/dhruv.jpg
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/images/navlogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kothariji/SyntaxMeets/74f10e80ae3e42908f9943e27ca06e99a0d53530/frontend/syntaxmeets/src/images/navlogo.png
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/images/nishant.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kothariji/SyntaxMeets/74f10e80ae3e42908f9943e27ca06e99a0d53530/frontend/syntaxmeets/src/images/nishant.jpg
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/images/ogimage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kothariji/SyntaxMeets/74f10e80ae3e42908f9943e27ca06e99a0d53530/frontend/syntaxmeets/src/images/ogimage.png
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/index.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kothariji/SyntaxMeets/74f10e80ae3e42908f9943e27ca06e99a0d53530/frontend/syntaxmeets/src/index.css
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import * as serviceWorker from './serviceWorker';
6 | import 'bootstrap/dist/css/bootstrap.min.css';
7 | import "react-loader-spinner/dist/loader/css/react-spinner-loader.css";
8 | import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles';
9 | import Mobile from "./components/Mobile/Mobile"
10 | import MediaQuery from 'react-responsive'
11 |
12 | const theme = createMuiTheme({
13 | palette: {
14 | primary: {
15 | light: '#00B4D8',
16 | main: '#00B4D8',
17 | dark: '#0077B6',
18 | contrastText: '#000',
19 | },
20 | info: {
21 | light: '#000A29',
22 | main: '#000A29',
23 | dark: '#002884',
24 | contrastText: '#fff',
25 | },
26 | secondary: {
27 | light: '#A38800',
28 | main: '#FFD500',
29 | dark: '#A38800',
30 | contrastText: '#fff',
31 | },
32 | },
33 | typography: {
34 | "fontFamily": `"Poppins", "Helvetica", "Arial", sans-serif`,
35 | button: {
36 | textTransform: 'none'
37 | }
38 | },
39 | overrides: {
40 | MuiOutlinedInput: {
41 | root: {
42 | position: 'relative',
43 | '& $notchedOutline': {
44 | borderColor: '#00B4D8',
45 | },
46 | '&:hover:not($disabled):not($focused):not($error) $notchedOutline': {
47 | borderColor: '#000a29',
48 | // Reset on touch devices, it doesn't add specificity
49 | '@media (hover: none)': {
50 | borderColor: '#000a29',
51 | },
52 | },
53 | '&$focused $notchedOutline': {
54 | borderColor: '#000a29',
55 | borderWidth: 1,
56 | },
57 | },
58 | },
59 | MuiFormLabel: {
60 | root: {
61 | '&$focused': {
62 | color: '#4A90E2'
63 | }
64 | }
65 | }
66 | }
67 | });
68 |
69 | ReactDOM.render(
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | ,
80 | document.getElementById('root')
81 | );
82 |
83 | // If you want your app to work offline and load faster, you can change
84 | // unregister() to register() below. Note this comes with some pitfalls.
85 | // Learn more about service workers: https://bit.ly/CRA-PWA
86 | serviceWorker.unregister();
87 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.0/8 are considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl, {
104 | headers: { 'Service-Worker': 'script' },
105 | })
106 | .then(response => {
107 | // Ensure service worker exists, and that we really are getting a JS file.
108 | const contentType = response.headers.get('content-type');
109 | if (
110 | response.status === 404 ||
111 | (contentType != null && contentType.indexOf('javascript') === -1)
112 | ) {
113 | // No service worker found. Probably a different app. Reload the page.
114 | navigator.serviceWorker.ready.then(registration => {
115 | registration.unregister().then(() => {
116 | window.location.reload();
117 | });
118 | });
119 | } else {
120 | // Service worker found. Proceed as normal.
121 | registerValidSW(swUrl, config);
122 | }
123 | })
124 | .catch(() => {
125 | console.log(
126 | 'No internet connection found. App is running in offline mode.'
127 | );
128 | });
129 | }
130 |
131 | export function unregister() {
132 | if ('serviceWorker' in navigator) {
133 | navigator.serviceWorker.ready
134 | .then(registration => {
135 | registration.unregister();
136 | })
137 | .catch(error => {
138 | console.error(error.message);
139 | });
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/services/axios.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | //named axiosExecute bcz we are excuting the code.
4 | const axiosExecute = axios.create({
5 | baseURL: "https://judge0-ce.p.rapidapi.com",
6 | headers: {
7 | "content-type": "application/json",
8 | "x-rapidapi-key": process.env.REACT_APP_ONLINE_JUDGE_API,
9 | "x-rapidapi-host": "judge0-ce.p.rapidapi.com",
10 | },
11 | })
12 |
13 |
14 | export default axiosExecute;
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/services/socket.js:
--------------------------------------------------------------------------------
1 | import io from "socket.io-client";
2 |
3 | export const socket = io.connect(
4 | process.env.REACT_APP_SYNTAXMEETS_BACKEND_API,{ transport: ["websocket"] }
5 | );
6 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom/extend-expect';
6 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/store/actions/chatActions.js:
--------------------------------------------------------------------------------
1 | import * as types from '../types.js';
2 |
3 |
4 | export function makeMessage(message) {
5 | return {
6 | type: types.SET_MESSAGES,
7 | message
8 | };
9 | }
10 | export function setMessage(message) {
11 | return {
12 | type: types.SET_MESSAGE,
13 | message
14 | };
15 | }
16 | export function whoIsTyping(typingUser){
17 | return {
18 | type: types.SET_TYPING_USER,
19 | typingUser
20 | };
21 | }
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/store/actions/editorActions.js:
--------------------------------------------------------------------------------
1 | import * as types from "../types.js";
2 | import axiosExecute from "../../services/axios.js";
3 |
4 | export function setCode(code) {
5 | return {
6 | type: types.SET_CODE,
7 | code,
8 | };
9 | }
10 | export function setLanguage(lang) {
11 | return {
12 | type: types.SET_LANG,
13 | lang,
14 | };
15 | }
16 | export function setFontSize(size) {
17 | return {
18 | type: types.SET_FONT_SIZE,
19 | size,
20 | };
21 | }
22 | export function setAutoCompletion(isactive) {
23 | return {
24 | type: types.SET_AUTO_COMPLETION,
25 | isactive,
26 | };
27 | }
28 | export function setCodeInput(input) {
29 | return {
30 | type: types.SET_CODE_INPUT,
31 | input,
32 | };
33 | }
34 | export function setCodeOutput(msg) {
35 | return {
36 | type: types.SET_CODE_OUTPUT,
37 | msg,
38 | };
39 | }
40 | export function setCodeIsCompiling(isactive) {
41 | return {
42 | type: types.SET_CODE_IS_COMPILING,
43 | isactive,
44 | };
45 | }
46 | export function setIsError(isactive) {
47 | return {
48 | type: types.SET_ERROR,
49 | isactive,
50 | };
51 | }
52 | export function setCodeError(err) {
53 | return {
54 | type: types.SET_CODE_ERROR,
55 | err,
56 | };
57 | }
58 | export function setPopup(typingUser) {
59 | return {
60 | type: types.SET_POPUP,
61 | typingUser,
62 | };
63 | }
64 |
65 | export const toggleFocusMode = () => {
66 | return (dispatch) => {
67 | dispatch({ type: types.TOGGLE_FOCUS_MODE });
68 | };
69 | };
70 |
71 | // API CALLS
72 |
73 | export const executeCode = (LangID, CODE, INPUT) => (dispatch) => {
74 | dispatch(setCodeIsCompiling(true));
75 | var codeToken = 0;
76 | axiosExecute
77 | .post(`/submissions`, {
78 | language_id: LangID,
79 | source_code: CODE,
80 | stdin: INPUT,
81 | })
82 | .then((res) => {
83 | codeToken = res.data.token;
84 | setTimeout(() => {
85 | axiosExecute
86 | .get("submissions/" + codeToken)
87 | .then((response) => {
88 | console.log(response);
89 | if (response.data.stderr !== null) {
90 | dispatch(setCodeIsCompiling(false));
91 | dispatch(setCodeError(response.data.stderr));
92 | dispatch(setIsError(true));
93 | } else {
94 | dispatch(setCodeOutput(response.data.stdout));
95 | dispatch(setCodeIsCompiling(false));
96 | }
97 | })
98 | .catch(function (error) {
99 | dispatch(setCodeIsCompiling(false));
100 | dispatch(
101 | setCodeError("Compilation Error: " + error.response.data.error)
102 | );
103 | dispatch(setIsError(true));
104 | });
105 | }, 7000);
106 | })
107 | .catch((err) => {
108 | dispatch(setCodeIsCompiling(false));
109 | console.log(err.response);
110 | });
111 | };
112 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/store/actions/roomActions.js:
--------------------------------------------------------------------------------
1 | import * as types from '../types.js';
2 |
3 |
4 | export function setRoomID(roomId) {
5 | return {
6 | type: types.SET_ROOOM_ID,
7 | roomId
8 | };
9 | }
10 | export function setId(id) {
11 | return {
12 | type: types.SET_USER_ID,
13 | id
14 | };
15 | }
16 | export function setUsers(users) {
17 | return {
18 | type: types.SET_USERS,
19 | users
20 | };
21 | }
22 | export function setName(name) {
23 | return {
24 | type: types.SET_NAME,
25 | name
26 | };
27 | }
28 | export function setPreviousUser(userObject){
29 | return {
30 | type: types.SET_PREVIOUS_USER,
31 | userObject
32 | };
33 | }
34 | export function removeUser(userObject){
35 | return {
36 | type: types.REMOVE_USER,
37 | userObject
38 | };
39 | }
40 | export function setGoToHome(isvalid){
41 | return {
42 | type: types.SET_GOTO_HOME,
43 | isvalid
44 | };
45 | }
46 | export function reset(){
47 | return {
48 | type: types.RESET,
49 |
50 | };
51 | }
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/store/actions/uiActions.js:
--------------------------------------------------------------------------------
1 | import * as types from "../types.js";
2 |
3 | export const setSnackBar = (msg, type) => {
4 | return (dispatch) => {
5 | dispatch({
6 | type: types.SET_SNACKBAR_MESSAGE,
7 | payload: { message: msg, type: type },
8 | });
9 | setTimeout(() => {
10 | dispatch({ type: "CLOSE_SNACKBAR" });
11 | }, 4000);
12 | };
13 | };
14 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/store/reducers/chatReducer.js:
--------------------------------------------------------------------------------
1 | import {
2 |
3 | SET_MESSAGES,
4 | SET_MESSAGE,
5 | SET_TYPING_USER,
6 |
7 | } from "../types";
8 |
9 | const initialState = {
10 | message: "",
11 | chat: [],
12 | typingUser: "",
13 | };
14 |
15 | export default function (state = initialState, action) {
16 | switch (action.type) {
17 | case SET_MESSAGES:
18 | return {
19 | ...state,
20 | chat:[...state.chat, action.message],
21 | };
22 | case SET_MESSAGE:
23 | return {
24 | ...state,
25 | message:action.message,
26 | };
27 | case SET_TYPING_USER:
28 | return {
29 | ...state,
30 | typingUser: action.typingUser,
31 | };
32 | default:
33 | return state;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/store/reducers/editorReducer.js:
--------------------------------------------------------------------------------
1 | import {
2 |
3 | SET_AUTO_COMPLETION,
4 | SET_POPUP,
5 | SET_CODE_ERROR,
6 | SET_ERROR,
7 | SET_CODE_IS_COMPILING,
8 | SET_CODE_INPUT,
9 | SET_CODE_OUTPUT,
10 | SET_FONT_SIZE,
11 | SET_LANG,
12 | SET_THEME,
13 | SET_CODE,
14 | SET_VISH,
15 |
16 | } from "../types";
17 |
18 | import {defaultValue} from "../../components/SyntaxEditor/LanguageData"
19 |
20 |
21 | const initialState = {
22 | code:defaultValue,
23 | lang: "C++",
24 | fontSize:16,
25 | autoCompletion: true,
26 | codeInput:"",
27 | codeOutput: "",
28 | isCompiling:false,
29 | codeError:"",
30 | isError:false,
31 | popup:false,
32 | };
33 |
34 | export default function (state = initialState, action) {
35 | switch (action.type) {
36 | case SET_CODE:
37 | return {
38 | ...state,
39 | code:action.code,
40 | };
41 | case SET_LANG:
42 | return {
43 | ...state,
44 | lang:action.lang,
45 | };
46 | case SET_FONT_SIZE:
47 | return {
48 | ...state,
49 | fontSize:action.size,
50 | };
51 | case SET_AUTO_COMPLETION:
52 | return {
53 | ...state,
54 | autoCompletion:action.isactive,
55 | };
56 | case SET_CODE_INPUT:
57 | return {
58 | ...state,
59 | codeInput: action.input,
60 | };
61 | case SET_CODE_OUTPUT:
62 | return {
63 | ...state,
64 | codeOutput: action.msg,
65 | };
66 | case SET_CODE_IS_COMPILING:
67 | return {
68 | ...state,
69 | isCompiling: action.isactive,
70 | };
71 | case SET_ERROR:
72 | return {
73 | ...state,
74 | isError: action.isactive,
75 | };
76 | case SET_CODE_ERROR:
77 | return {
78 | ...state,
79 | codeError: action.err,
80 | };
81 | case SET_POPUP:
82 | return {
83 | ...state,
84 | goToHome: action.isvalid,
85 | };
86 | default:
87 | return state;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/store/reducers/roomReducer.js:
--------------------------------------------------------------------------------
1 | import {
2 |
3 | SET_ROOOM_ID,
4 | SET_NAME,
5 | SET_USERS,
6 | SET_USER_ID,
7 | SET_PREVIOUS_USER,
8 | REMOVE_USER,
9 | SET_GOTO_HOME,
10 | } from "../types";
11 |
12 | import {generateRoomId} from "../../util/util"
13 |
14 |
15 | const initialState = {
16 | roomId: generateRoomId(),
17 | name: "",
18 | id:null,
19 | users: {},
20 | previousUser:{},
21 | goToHome:false,
22 | };
23 |
24 | export default function (state = initialState, action) {
25 | switch (action.type) {
26 | case SET_ROOOM_ID:
27 | return {
28 | ...state,
29 | roomId:action.roomId,
30 | };
31 | case SET_NAME:
32 | return {
33 | ...state,
34 | name:action.name,
35 | };
36 | case SET_USERS:
37 | return {
38 | ...state,
39 | users:{...state.users,...action.users}
40 | };
41 | case REMOVE_USER:
42 | const olduser = action.userObject.id;
43 | const {[olduser]:remove, ...newState} = state.users;
44 | console.log(newState);
45 | return { ...state,
46 | users:newState,
47 | };
48 | case SET_USER_ID:
49 | return {
50 | ...state,
51 | id: action.id,
52 | };
53 | case SET_PREVIOUS_USER:
54 | return {
55 | ...state,
56 | previousUser: action.userObject,
57 | };
58 | case SET_GOTO_HOME:
59 | return {
60 | ...state,
61 | goToHome: action.isvalid,
62 | };
63 | default:
64 | return state;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/store/reducers/uiReducer.js:
--------------------------------------------------------------------------------
1 | import {
2 | SET_SNACKBAR_MESSAGE,
3 | CLOSE_SNACKBAR,
4 | TOGGLE_FOCUS_MODE,
5 | } from "../types";
6 |
7 | const initialState = {
8 | setSnackBarMessage: null,
9 | isSnackBarOpen: false,
10 | snackBarType: "info",
11 | isFocusMode: false,
12 | };
13 |
14 | export default function (state = initialState, action) {
15 | switch (action.type) {
16 | case SET_SNACKBAR_MESSAGE:
17 | return {
18 | ...state,
19 | isSnackBarOpen: true,
20 | snackBarType: action.payload.type,
21 | setSnackBarMessage: action.payload.message,
22 | };
23 | case CLOSE_SNACKBAR:
24 | return {
25 | ...state,
26 | isSnackBarOpen: false,
27 | };
28 |
29 | case TOGGLE_FOCUS_MODE:
30 | return {
31 | ...state,
32 | isFocusMode: !state.isFocusMode,
33 | };
34 | default:
35 | return state;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/store/store.js:
--------------------------------------------------------------------------------
1 | import { createStore, combineReducers, applyMiddleware, compose } from "redux";
2 | import thunk from "redux-thunk";
3 | import chatReducer from "./reducers/chatReducer";
4 | import editorReducer from "./reducers/editorReducer";
5 | import roomReducer from "./reducers/roomReducer";
6 | import uiReducer from "./reducers/uiReducer";
7 |
8 | const initialState = {};
9 |
10 | //ThunkMiddleware
11 | const middleware = [thunk];
12 |
13 | // Reducers Object
14 | const reducers = combineReducers({
15 | CHAT: chatReducer,
16 | ROOM: roomReducer,
17 | EDITOR:editorReducer,
18 | UI:uiReducer
19 | });
20 |
21 | const rootReducer = (state, action) => {
22 | if (action.type === 'RESET') {
23 | state = undefined
24 | }
25 |
26 | return reducers(state, action)
27 | }
28 |
29 | const composeEnhancers =
30 | (process.env.NODE_ENV !== 'production' &&
31 | typeof window !== 'undefined' &&
32 | window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) ||
33 | compose;
34 |
35 | const enhancer = composeEnhancers(applyMiddleware(...middleware));
36 | const store = createStore(rootReducer, initialState, enhancer);
37 |
38 | export default store;
39 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/store/types.js:
--------------------------------------------------------------------------------
1 | // room actions Types
2 | export const SET_ROOOM_ID = "SET_ROOOM_ID";
3 | export const SET_NAME = "SET_NAME";
4 | export const SET_USERS = "SET_USERS";
5 | export const SET_USER_ID = "SET_USER_ID";
6 | export const SET_PREVIOUS_USER = "SET_PREVIOUS_USER";
7 | export const REMOVE_USER = "REMOVE_USER";
8 | export const SET_GOTO_HOME = "SET_GOTO_HOME";
9 | export const RESET = "RESET";
10 | export const TOGGLE_FOCUS_MODE = "TOGGLE_FOCUS_MODE";
11 |
12 | // Editor actions Types
13 | export const SET_CODE = "SET_CODE";
14 | export const SET_LANG = "SET_LANG";
15 | export const SET_THEME = "SET_THEME";
16 | export const SET_FONT_SIZE = "SET_FONT_SIZE";
17 | export const SET_AUTO_COMPLETION = "SET_AUTO_COMPLETION";
18 | export const SET_CODE_INPUT = "SET_CODE_INPUT";
19 | export const SET_CODE_OUTPUT = "SET_CODE_OUTPUT";
20 | export const SET_CODE_IS_COMPILING = "SET_CODE_IS_COMPILING";
21 | export const SET_ERROR = "SET_ERROR"; //boolean
22 | export const SET_CODE_ERROR = "SET_CODE_ERROR"; //boolean
23 | export const SET_POPUP = "SET_POPUP";
24 |
25 | //chat actions Types
26 | export const SET_MESSAGE = "SET_MESSAGE";
27 | export const SET_MESSAGES = "SET_MESSAGES";
28 | export const SET_TYPING_USER = "SET_TYPING_USER";
29 |
30 | //SnackBar Types
31 | export const SET_SNACKBAR_MESSAGE = "SET_SNACKBAR_MESSAGE";
32 | export const CLOSE_SNACKBAR = "CLOSE_SNACKBAR";
33 |
--------------------------------------------------------------------------------
/frontend/syntaxmeets/src/util/util.js:
--------------------------------------------------------------------------------
1 | export const generateRoomId = () => {
2 | var tempId = "";
3 | var characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
4 | var charactersLength = characters.length;
5 | for (var i = 0; i < 12; i++) {
6 | tempId += characters.charAt(Math.floor(Math.random() * charactersLength));
7 | if ((i + 1) % 4 === 0 && i !== 11) {
8 | tempId += "-";
9 | }
10 | }
11 | return tempId;
12 | };
13 |
14 | export const validateRoomID = (roomId) => {
15 | var patt = new RegExp("(([A-Za-z]{4})(-)){2}[A-Za-z]{4}");
16 | return patt.test(roomId.trim()) && roomId.length == 14;
17 | };
18 |
19 | export const getExtensionByLangCode = (langCode) => {
20 | switch (langCode) {
21 | case "C++":
22 | return "cpp";
23 | case "C":
24 | return "c";
25 | case "JAVA":
26 | return "java";
27 | case "Python":
28 | return "py";
29 | case "JavaScript":
30 | return "js";
31 | case "TypeScript":
32 | return "ts";
33 | case "Clojure":
34 | return "clj";
35 | case "C#":
36 | return "cs";
37 | case "COBOL":
38 | return "cbl";
39 | case "COBOL":
40 | return "cob";
41 | case "Erlang":
42 | return "erl";
43 | case "Go":
44 | return "go";
45 | case "Python":
46 | return "py";
47 | case "FortRan":
48 | return "f90";
49 | case "Groovy":
50 | return "groovy";
51 | case "Kotlin":
52 | return "kt";
53 | case "PHP":
54 | return "php";
55 | case "R":
56 | return "r";
57 | case "Ruby":
58 | return "rb";
59 | case "SQL":
60 | return "sql";
61 | case "Swift":
62 | return "swift";
63 | default:
64 | return "txt";
65 | }
66 | };
67 |
--------------------------------------------------------------------------------