├── .firebase
└── hosting.YnVpbGQ.cache
├── .firebaserc
├── .gitignore
├── README.md
├── firebase.json
├── functions
├── .gitignore
├── index.js
├── package-lock.json
├── package.json
└── ui-debug.log
├── package-lock.json
├── package.json
├── public
├── 404.html
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
├── robots.txt
└── worker.js
├── src
├── App.css
├── App.js
├── Assets
│ ├── Fest.png
│ ├── Logo.svg
│ ├── background.png
│ ├── camera.svg
│ └── hack.png
├── Auth
│ ├── Login.js
│ └── Signup.js
├── Components
│ ├── Alert
│ │ └── index.js
│ ├── Cards
│ │ ├── AssignmentCard.js
│ │ ├── ClassCard.js
│ │ ├── CourseCard.js
│ │ ├── ForumQuestionCard.js
│ │ ├── ResourceCard.js
│ │ └── VideoCard.js
│ ├── Containers
│ │ ├── AssignmentContainer.js
│ │ ├── ClassesContainer.js
│ │ ├── CourseContainer.js
│ │ └── ViewSubmissionContainer.js
│ ├── Footer
│ │ └── Footer.js
│ ├── Forms
│ │ ├── AddAdminForm.js
│ │ ├── AddAssignmentForm.js
│ │ ├── AddClassForm.js
│ │ ├── AddCourseForm.js
│ │ ├── AddNotificationForm.js
│ │ ├── AddQuestionForm.js
│ │ ├── AddResourceForm.js
│ │ ├── AddVideoForm.js
│ │ ├── EditStudentForm.js
│ │ ├── EditTeacherForm.js
│ │ └── UploadAssignment.js
│ ├── Info
│ │ ├── Info.js
│ │ └── TeacherInfo.js
│ ├── Modal
│ │ └── index.js
│ ├── Navbar
│ │ └── Navbar.js
│ ├── Notification
│ │ └── index.js
│ ├── Slider
│ │ └── index.js
│ └── Table
│ │ ├── AdminTable.js
│ │ ├── StudentTable.js
│ │ ├── SubmissionsTable.js
│ │ └── TeacherTable.js
├── Dashboards
│ ├── admin
│ │ ├── AdminDashboard.js
│ │ └── pages
│ │ │ ├── Admins.js
│ │ │ ├── Assignments.js
│ │ │ ├── Course.js
│ │ │ ├── Courses.js
│ │ │ ├── Overview.js
│ │ │ ├── Student.js
│ │ │ ├── Students.js
│ │ │ ├── Teacher.js
│ │ │ └── Teachers.js
│ ├── forum
│ │ └── StudentForum.js
│ ├── student
│ │ ├── StudentDashboard.js
│ │ └── pages
│ │ │ └── Home.js
│ └── teacher
│ │ ├── TeacherDashboard.js
│ │ └── pages
│ │ ├── MyAssignments.js
│ │ ├── MyClasses.js
│ │ └── TeacherOverview.js
├── Errorpage.js
├── Hooks
│ └── useForm.js
├── Routes.js
├── Store
│ ├── actions
│ │ ├── assignmentActions.js
│ │ ├── authActions.js
│ │ ├── classActions.js
│ │ ├── courseActions.js
│ │ ├── forumActions.js
│ │ ├── notificationActions.js
│ │ ├── studentActions.js
│ │ └── teacherActions.js
│ └── reducers
│ │ ├── authReducer.js
│ │ ├── coursesReducer.js
│ │ ├── rootReducer.js
│ │ └── studentReducer.js
├── config
│ └── fbConfig.js
└── index.js
└── yarn.lock
/.firebase/hosting.YnVpbGQ.cache:
--------------------------------------------------------------------------------
1 | favicon.ico,1613543104297,eae62e993eb980ec8a25058c39d5a51feab118bd2100c4deebb2a9c158ec11f9
2 | logo192.png,1613543104297,3ee59515172ee198f3be375979df15ac5345183e656720a381b8872b2a39dc8b
3 | logo512.png,1613543104297,ee7e2f3fdb8209c4b6fd7bef6ba50d1b9dba30a25bb5c3126df057e1cb6f5331
4 | robots.txt,1613543104297,bfe106a3fb878dc83461c86818bf74fc1bdc7f28538ba613cd3e775516ce8b49
5 | index.html,1618356686368,a1f61dc615a28feac112398ecf70c92359aba66a4da4ec9aa5b97d9f39661887
6 | asset-manifest.json,1618356686371,f5e8f8f173fcdefb00a55b75729352451a04c5507f8ec72a95d3125e3098333e
7 | static/css/main.4b1710c1.chunk.css,1618356686371,7fbf11dd061295cd434223949686b1eb5e62d591c523df2df7c51ca270b22e96
8 | static/css/main.4b1710c1.chunk.css.map,1618356686396,0bf46ddf9c5c57e9b2c837044c3e917d6e97ffcc85ca733900c2870cc2918030
9 | static/js/2.9aaabe01.chunk.js.LICENSE.txt,1618356686395,db5e990c63366acc28ee4d68a8b06cf6f262336190be423eb925127eea05a96c
10 | static/js/runtime-main.32128dd0.js,1618356686377,c895eadb410e19377ca0e93a9573f5fdc84370570d1cfef903360a26a58772d5
11 | static/js/runtime-main.32128dd0.js.map,1618356686395,b8d9b9714d21429e4986251035918ea299774f6d32cb3915d4694ddb2eb36030
12 | static/media/camera.dd4016c6.svg,1618356686395,8310c1d9d98c7993f6a6b42bd3a8085d8be13171d9ab9a526008f4444d02adf7
13 | static/media/Logo.a00b17f4.svg,1618356686371,0a40b20644a1921749cae8161947f6dd71ce88ceae1ca32cadb34e6570b41d7f
14 | manifest.json,1618344024926,2c5c63743da10d9e03cc448f0b87a754b86b7342b986e40cd804831c2b776589
15 | 404.html,1615468751007,daa499dd96d8229e73235345702ba32f0793f0c8e5c0d30e40e37a5872be57aa
16 | worker.js,1618344024926,a9a27abba09f6c5db60a195502a8be40655a6dfc40f5af7111058ab7092b1f31
17 | static/js/main.ab1331d9.chunk.js,1618356686395,5ddb969b8f81a1b2cf9f66eb2bd2169286bac5aa3834d631f71757da045182e7
18 | static/css/2.8461011e.chunk.css,1618356686395,f9a18b309596300ed4ef5190fa0d8ec908bcd0116cd35134dbe06f4df54f4be5
19 | static/js/main.ab1331d9.chunk.js.map,1618356686395,b8ab40125cccc0ac387c9497d9df576a8db8c6c19de4ba9cf704c467a0411c14
20 | static/css/2.8461011e.chunk.css.map,1618356686396,4c35d3ea6451ab1066fa062005b5292bfa8f70369c0d201527fbe21a4373c9c9
21 | static/js/2.9aaabe01.chunk.js,1618356686396,e2c4b44db33a6295a91d5adf0c829dae0a35492a5150332e6bb60f209d0ba8e1
22 | static/media/background.08e12498.png,1618356686397,3f63ae097e13e9fff1a6054f867a66b655fa45907227a28ccbce7315fa2c3bec
23 | static/js/2.9aaabe01.chunk.js.map,1618356686397,7ebf9cc0d4aaa54d86c5ae32e551e12cc8606267df764d5c47492fd39df9a1cf
24 |
--------------------------------------------------------------------------------
/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "default": "elearning-project-5423b"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
25 | .vercel
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Learning Management System - Project
2 |
3 | ### Tech Stack
4 |
5 | - React.js (create-react-app)
6 | - Bootstrap (reactstrap)
7 | - react-redux-firebase
8 | - react-redux
9 | - redux-firestore
10 | - Firebase
11 |
12 | ### How to run it locally
13 |
14 | 1. Install VS Code.
15 | 2. Clone the repository using github [How to](https://blog.velingeorgiev.com/how-to-clone-git-project-with-visual-studio-code).
16 | 3. In the terminal, enter `npm install` to install all dependencies.
17 | 4. Enter `npm run start` after the dependencies are installed.
18 | 5. The site will be visible on `localhost:3000`
19 |
--------------------------------------------------------------------------------
/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "hosting": {
3 | "public": "build",
4 | "ignore": [
5 | "firebase.json",
6 | "**/.*",
7 | "**/node_modules/**"
8 | ],
9 | "rewrites": [
10 | {
11 | "source": "**",
12 | "destination": "/index.html"
13 | }
14 | ]
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/functions/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
--------------------------------------------------------------------------------
/functions/index.js:
--------------------------------------------------------------------------------
1 | const functions = require("firebase-functions");
2 | const admin = require('firebase-admin');
3 | const cors = require('cors')({origin: true})
4 | admin.initializeApp(functions.config().firebase)
5 |
6 | const createNotification = ((notification) => {
7 | return admin.firestore().collection('notifications')
8 | .add(notification)
9 | .then(doc => console.log('notification added', doc));
10 | });
11 |
12 |
13 | exports.newNotificationAdded = functions
14 | .firestore
15 | .document('adminnotifications/{adminnotificationId}')
16 | .onCreate(
17 | doc =>{
18 | const newNotification = doc.data();
19 | return createNotification(newNotification)
20 | }
21 | )
22 |
23 |
24 | exports.addAdmin = functions.https.onRequest(async (req, res) => {
25 | cors(req, res, async() => {
26 | try {
27 | const newAdmin = {
28 | email: req.body.email,
29 | password: req.body.password,
30 | }
31 |
32 | const adminRecord = await admin
33 | .auth()
34 | .createUser(newAdmin);
35 |
36 | const userId = adminRecord.uid;
37 |
38 | await admin.firestore().collection("users").doc(userId).set({
39 | email: req.body.email,
40 | name: req.body.name,
41 | userType: 'Admin',
42 | password: req.body.password,
43 | phone: req.body.phone,
44 | });
45 |
46 | return { result: 'The new admin has been successfully created.' };
47 | } catch (error) {
48 | console.log(error)
49 | }
50 | })
51 | })
--------------------------------------------------------------------------------
/functions/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "functions",
3 | "description": "Cloud Functions for Firebase",
4 | "scripts": {
5 | "serve": "firebase emulators:start --only functions",
6 | "shell": "firebase functions:shell",
7 | "start": "npm run shell",
8 | "deploy": "firebase deploy --only functions",
9 | "logs": "firebase functions:log"
10 | },
11 | "engines": {
12 | "node": "12"
13 | },
14 | "main": "index.js",
15 | "dependencies": {
16 | "cors": "^2.8.5",
17 | "firebase-admin": "^9.2.0",
18 | "firebase-functions": "^3.11.0"
19 | },
20 | "devDependencies": {
21 | "firebase-functions-test": "^0.2.0"
22 | },
23 | "private": true
24 | }
25 |
--------------------------------------------------------------------------------
/functions/ui-debug.log:
--------------------------------------------------------------------------------
1 | Web / API server started at http://localhost:4005
2 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lms",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@carbon/icons-react": "^10.28.0",
7 | "@testing-library/jest-dom": "^5.11.4",
8 | "@testing-library/react": "^11.1.0",
9 | "@testing-library/user-event": "^12.1.10",
10 | "bootstrap": "^4.6.0",
11 | "boxicons": "^2.0.7",
12 | "firebase": "^8.2.9",
13 | "react": "^17.0.1",
14 | "react-bootstrap": "^1.5.0",
15 | "react-dom": "^17.0.1",
16 | "react-hook-form": "^6.15.5",
17 | "react-redux": "^7.2.2",
18 | "react-redux-firebase": "^3.10.0",
19 | "react-redux-firestore": "0.0.1",
20 | "react-router-dom": "^5.2.0",
21 | "react-scripts": "4.0.3",
22 | "react-toastify": "^7.0.3",
23 | "reactstrap": "^8.9.0",
24 | "redux": "^4.0.5",
25 | "redux-firestore": "^0.15.0",
26 | "redux-logger": "^3.0.6",
27 | "redux-thunk": "^2.3.0",
28 | "uid": "^2.0.0",
29 | "video-react": "^0.14.1",
30 | "web-vitals": "^1.0.1"
31 | },
32 | "scripts": {
33 | "start": "react-scripts start",
34 | "build": "react-scripts build",
35 | "test": "react-scripts test",
36 | "eject": "react-scripts eject"
37 | },
38 | "eslintConfig": {
39 | "extends": [
40 | "react-app",
41 | "react-app/jest"
42 | ]
43 | },
44 | "browserslist": {
45 | "production": [
46 | ">0.2%",
47 | "not dead",
48 | "not op_mini all"
49 | ],
50 | "development": [
51 | "last 1 chrome version",
52 | "last 1 firefox version",
53 | "last 1 safari version"
54 | ]
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Page Not Found
7 |
8 |
23 |
24 |
25 |
26 |
404
27 |
Page Not Found
28 |
The specified file was not found on this website. Please check the URL for mistakes and try again.
29 |
Why am I seeing this?
30 |
This page was generated by the Firebase Command-Line Interface. To modify it, edit the 404.html
file in your project's configured public
directory.
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shashankbhat2/lms/f40dd5f6c42ac1a87dbf1b73ae5a8cf64c85c09e/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 | AcadOnline - LMS
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shashankbhat2/lms/f40dd5f6c42ac1a87dbf1b73ae5a8cf64c85c09e/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shashankbhat2/lms/f40dd5f6c42ac1a87dbf1b73ae5a8cf64c85c09e/public/logo512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "AcadOnline - LMS",
3 | "name": "AcadOnline - LMS",
4 | "icons": [
5 | {
6 | "src": "./logo192.png",
7 | "type": "image/png",
8 | "sizes": "192x192"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff",
15 | "prefer_related_applications":false
16 | }
17 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/public/worker.js:
--------------------------------------------------------------------------------
1 |
2 | var CACHE_NAME = 'pwa-task-manager';
3 | var urlsToCache = [
4 | '/',
5 | '/completed'
6 | ];
7 |
8 | // Install a service worker
9 | self.addEventListener('install', event => {
10 | // Perform install steps
11 | event.waitUntil(
12 | caches.open(CACHE_NAME)
13 | .then(function(cache) {
14 | console.log('Opened cache');
15 | return cache.addAll(urlsToCache);
16 | })
17 | );
18 | });
19 |
20 | // Cache and return requests
21 | self.addEventListener('fetch', event => {
22 | event.respondWith(
23 | caches.match(event.request)
24 | .then(function(response) {
25 | // Cache hit - return response
26 | if (response) {
27 | return response;
28 | }
29 | return fetch(event.request);
30 | }
31 | )
32 | );
33 | });
34 |
35 | // Update a service worker
36 | self.addEventListener('activate', event => {
37 | var cacheWhitelist = ['pwa-task-manager'];
38 | event.waitUntil(
39 | caches.keys().then(cacheNames => {
40 | return Promise.all(
41 | cacheNames.map(cacheName => {
42 | if (cacheWhitelist.indexOf(cacheName) === -1) {
43 | return caches.delete(cacheName);
44 | }
45 | })
46 | );
47 | })
48 | );
49 | });
50 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | *{
2 | padding: 0;
3 | margin: 0;
4 | box-sizing: border-box;
5 | }
6 |
7 | body{
8 | margin:0px;
9 | font-family: 'Source Sans Pro' !important;
10 | height:100%;
11 | }
12 |
13 | .welcome-card{
14 | font-weight: 600;
15 | width: 100%;
16 | padding: 20px;
17 | height: auto;
18 | border: none !important;
19 | box-shadow: 1px 4px 12px rgba(3, 0, 159, 0.1);
20 | }
21 | .welcome-card > h2{
22 | color: #4f4f4f;
23 | font-family: 'Source Sans Pro';
24 | }
25 | .username{
26 | color: #03009F;
27 | font-family: 'Source Sans Pro';
28 | font-size: 35px;
29 | font-weight: 550;
30 | margin: 0 5px;
31 | }
32 |
33 | .class-helper{
34 | color: #4f4f4f;
35 | text-align: center;
36 | }
37 | .class-link{
38 | color: white;
39 | text-decoration: none !important;
40 | }
41 | .class-link:hover{
42 | color: white;
43 | }
44 | .class-card{
45 | font-family: 'Source Sans Pro';
46 | box-shadow: 2px 4px 10px rgba(0, 0, 0, 0.1);
47 | border: none !important;
48 | padding: 20px;
49 | }
50 | .class-btn{
51 | text-transform: uppercase;
52 | background: #219653 !important;
53 | font-weight: 550 !important;
54 | border: none !important;
55 | }
56 | .table-title{
57 | color: #03009F;
58 | font-weight: 550;
59 | }
60 | .suspend-button{
61 | width: 100%;
62 | font-weight: 550 !important;
63 | }
64 | .basic-info{
65 | padding: 20px;
66 | background: #FFFFFF;
67 | border: none !important;
68 | box-shadow: -1px 10px 19px rgba(3, 0, 159, 0.1);
69 | }
70 |
71 | .basic-info > h4{
72 | color: #2F80ED;
73 | font-weight: 550;
74 | }
75 |
76 | .info-label{
77 | color: #4F4F4F;
78 | font-weight: 500;
79 | font-size: 18px;
80 | }
81 |
82 | .s-name{
83 | color: black;
84 | font-weight: 550;
85 | }
86 |
87 | .selector{
88 | cursor: pointer !important;
89 | }
90 |
91 | .toast{
92 | margin: 5px !important;
93 | border-radius: 0px !important;
94 | border: none !important;
95 | position: relative !important;
96 | float: right !important;
97 | font-weight: 550 !important;
98 | width: 200px !important;
99 | font-size: 18px !important;
100 | }
101 |
102 | .errorToast{
103 | border-left: red 3px solid !important;
104 | margin: auto !important;
105 | float: left !important;
106 | font-size: 14px !important;
107 | }
108 |
109 | .successToast{
110 | border-left: #32B6A2 3px solid !important;
111 | }
112 |
113 | .upload-wrapper{
114 | padding: 5px;
115 | border-radius: 50px;
116 | border: none;
117 | background: transparent;
118 | z-index: 1;
119 | position: relative;
120 | top: 100px;
121 | right: 5%;
122 | }
123 |
124 | .img{
125 | width: 150px !important;
126 | object-fit: cover;
127 |
128 | }
129 | .camera-icon{
130 | background:white;
131 | width:40px;
132 | height:40px;
133 | border-radius:50%;
134 | display:flex;
135 | justify-content: center;
136 | position:absolute;
137 | bottom:5px;
138 | right:-20px;
139 | z-index: 1;
140 | padding: 10px;
141 | cursor: pointer;
142 | }
143 |
144 | .button{
145 | border: none !important;
146 | font-weight: 550 !important;
147 | text-transform: uppercase;
148 | width: 80%;
149 | margin-top: auto;
150 | font-size: 14px !important;
151 | }
152 |
153 | .card-button{
154 | border: none !important;
155 | font-weight: 550 !important;
156 | text-transform: uppercase;
157 | width: auto;
158 | margin-top: 10px;
159 | font-size: 14px !important;
160 | }
161 |
162 | .course-card{
163 | margin: 5px;
164 | border: none !important;
165 | box-shadow: -2px 5px 18px rgba(3, 0, 159, 0.15);
166 | transition: all cubic-bezier(0.075, 0.82, 0.165, 1) 2s;
167 | }
168 |
169 |
170 | .course-card:hover{
171 | transform: scale(1.05);
172 | }
173 |
174 |
175 | .navy{
176 | background-color: #0021CA !important;
177 | }
178 |
179 | .subtitle{
180 | color: black !important;
181 | font-weight: 500;
182 | }
183 |
184 |
185 | .profile-menu{
186 | margin-right: 10px !important;
187 | }
188 |
189 | .profile-dropdown{
190 | color: white !important;
191 | font-family: 'Source Sans Pro';
192 | font-weight: 550 !important;
193 | background-color: transparent !important;
194 | margin: 0 !important;
195 | border: 1px solid !important;
196 | }
197 | .profile-dropdown:active{
198 | background-color: transparent !important;
199 | outline: none !important;
200 | }
201 |
202 | .profile-dropdown:focus{
203 | background-color: transparent !important;
204 | outline: none !important;
205 | }
206 |
207 | /* .navbar{
208 | background: #AFD1FF !important;
209 | } */
210 |
211 | .slider-img{
212 | width:100%;
213 | height:400px;
214 | }
215 | .carousel{
216 | width:100%;
217 | }
218 |
219 | @media (max-width: 767px) {
220 | .slider-img{
221 | width:100%;
222 | height:200px;
223 | }
224 | }
225 |
226 | .question{
227 | color: navy;
228 | font-size: 18px;
229 | font-family: 'Source Sans Pro', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
230 | }
231 | .title{
232 | font-family: 'Montserrat', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
233 | font-weight: 550;
234 | color: darkblue;
235 | }
236 | .user{
237 | font-size: 16px;
238 | font-weight:500;
239 | }
240 |
241 | .q-card{
242 | box-shadow: 1px 4px 12px rgba(3, 0, 159, 0.1);
243 | border: none !important;
244 | }
245 |
246 | .footer{
247 | text-align: center;
248 | font-size: 16px;
249 | font-family: 'Source Sans Pro';
250 | margin: auto;
251 | background-color: #AFD1FF;
252 | color: navy;
253 | position: relative;
254 | bottom: 0;
255 | width: 100%;
256 | overflow: hidden;
257 | width: 100%;
258 | }
259 |
260 | .notif-heading{
261 | background: #03009F !important;
262 | font-family: 'Source Sans Pro';
263 | font-weight: 550;
264 | text-align: center;
265 | color: white;
266 | border: none;
267 | }
268 |
269 | .add-notif{
270 | width: 100%;
271 | font-family: 'Source Sans Pro';
272 | text-transform: uppercase;
273 | font-weight: 550 !important;
274 | }
275 |
276 | .notifications{
277 | border: none;
278 | box-shadow: 0px 4px 4px rgba(3, 0, 159, 0.2);
279 | }
280 | .link{
281 | color: white !important;
282 | text-decoration: none !important;
283 | }
284 | .course-title{
285 | color: #4F4F4F;
286 | }
287 |
288 | .c-title{
289 | color: black;
290 | font-weight: 550;
291 | }
292 |
293 | .video-title{
294 | font-size: 20px;
295 | font-weight: 550;
296 | }
297 |
298 | .video-card{
299 | margin: 0px 5px;
300 | padding: 10px;
301 | }
302 |
303 | .play-button{
304 | background: navy !important;
305 | }
306 | .view-button{
307 | background:royalblue !important;
308 | }
309 |
310 | .card-link{
311 | text-decoration: none;
312 | color: black;
313 | }
314 |
315 | .a-card{
316 | margin: 5px;
317 | border: none !important;
318 | box-shadow: -2px 5px 18px rgba(3, 0, 159, 0.15);
319 | }
320 |
321 | .a-title{
322 | color:black;
323 | font-size: 20px;
324 | font-weight: 550;
325 | }
326 |
327 | .edit{
328 | background:crimson !important;
329 | }
330 |
331 | .a-btn{
332 | border: none !important;
333 | }
334 |
335 | .view{
336 | background: #03009F !important;
337 | }
338 |
339 | .a-subtitle{
340 | font-size: 16px !important;
341 | margin: 10px 0px;
342 | font-weight: 550;
343 | color: darkslategrey !important;
344 | }
345 |
346 | .comment-user{
347 | color: #2F80ED;
348 | font-weight: 550;
349 | }
350 | .answers{
351 | color: #03009F;
352 | font-weight: 600;
353 | }
354 |
355 | .comment{
356 | border-radius: 0% !important;
357 | width: auto;
358 | position: relative;
359 | margin: 10px;
360 | }
361 |
362 | .comment-answer{
363 | color: black;
364 | font-weight: 600;
365 | }
366 |
367 | .question-card{
368 | width: auto;
369 | padding: 10px;
370 | height: auto;
371 | }
372 | .comment-section{
373 | padding: 10px;
374 | background: #F5F5F5;
375 | border: 1px solid lightgray;
376 | width: auto;
377 | height: auto;
378 | }
379 | .commenter{
380 | color: #03009F;
381 | font-weight: 550;
382 | }
383 |
384 | .comments{
385 | width: auto;
386 | padding: 10px;
387 | border: 1px solid lightgray;
388 | background-color: white;
389 | }
390 | .user{
391 | color: crimson;
392 | font-weight: 600;
393 | }
394 | .forum-question{
395 | color: darkblue;
396 | font-size: 25px;
397 | font-weight: 600;
398 | }
399 |
400 | .topic{
401 | width: auto;
402 | background-color:transparent !important;
403 | color: #219653 !important;
404 | border: #219653 1px solid;
405 | }
406 |
407 | .remove-question{
408 | cursor: pointer;
409 | color: red;
410 | font-weight: 550 !important;
411 | font-size: 12px !important;
412 | }
413 |
414 | .empty-div{
415 | border-radius: 10px;
416 | border: 0.1px solid #dae4ee;
417 | padding: 100px;
418 | width: 100%;
419 | }
420 | .center-text{
421 | text-align: center;
422 | }
423 |
424 |
425 | .signup-box{
426 | height: 95vh;
427 | position:relative;
428 | background-size: cover;
429 | background-repeat: no-repeat;
430 | background-image: linear-gradient(0deg, rgba(3, 0, 159, 0.6), rgba(3, 0, 159, 0.6)),url('./Assets/background.png');
431 | }
432 |
433 | .error{
434 | color: orangered;
435 | margin: 8px 0px;
436 | font-weight: 550 !important;
437 | font-size: 16px !important;
438 | }
439 |
440 | .logo-container{
441 | width: 100%;
442 | height: 100px;
443 | overflow: hidden;
444 | z-index: 0;
445 | background-color: #2D9CDB;
446 | position: absolute;
447 | top: 40%;
448 | text-align: center;
449 | }
450 |
451 | .logo{
452 | margin-top: 10px;
453 | }
454 |
455 | .signup-container{
456 | font-family: 'Source Sans Pro' !important;
457 | font-size: 18px;
458 | font-weight: 600;
459 | margin-top: 50px;
460 | }
461 |
462 | .signup-button{
463 | margin: 10px 0px;
464 | font-weight: 600 !important;
465 | width: 20%;
466 | }
467 |
468 | .logo-mobile{
469 | display: none;
470 | }
471 |
472 | .login-button{
473 | width: 20%;
474 | }
475 |
476 | .heading{
477 | font-family: 'Montserrat', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
478 | color: #03009F;
479 | font-style: normal;
480 | font-weight: bold;
481 | }
482 |
483 | .login-helper{
484 | margin: 10px 0px;
485 | font-size: 16px;
486 | font-weight: 500 !important;
487 | }
488 |
489 | .login-helper > a {
490 | cursor: pointer;
491 | color:#2D9CDB !important;
492 | font-weight: 600;
493 | }
494 |
495 |
496 |
497 | @media (max-width: 767px) {
498 | .signup-box{
499 | height: auto;
500 | display: flex;
501 | background: none;
502 | }
503 | .signup-container{
504 | margin-top: 150px;
505 | margin-bottom: 50px;
506 | }
507 | }
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import {Redirect, Route, Switch } from 'react-router-dom';
2 | import React from 'react'
3 | import './App.css';
4 | import Login from './Auth/Login';
5 | import Signup from './Auth/Signup';
6 | import AdminDashboard from './Dashboards/admin/AdminDashboard'
7 | import StudentDashboard from './Dashboards/student/StudentDashboard'
8 | import TeacherDashboard from './Dashboards/teacher/TeacherDashboard'
9 | import {connect} from 'react-redux';
10 | import './App.css'
11 | import ErrorPage from './Errorpage';
12 | import CustomNavbar from './Components/Navbar/Navbar';
13 | import {ADMIN_ROUTES, STUDENT_ROUTES, TEACHER_ROUTES} from './Routes'
14 | import CustomAlert from './Components/Alert'
15 |
16 |
17 |
18 |
19 | class App extends React.Component{
20 | render(){
21 | const {profile,auth} = this.props;
22 |
23 | var links;
24 |
25 | if(profile.userType === "Admin"){
26 | links = ADMIN_ROUTES;
27 | }else if(profile.userType === "Teacher"){
28 | links = TEACHER_ROUTES;
29 | }else{
30 | links = STUDENT_ROUTES;
31 | }
32 |
33 | return(
34 |
35 | {auth && !auth.uid ? '' :
}
36 |
37 |
38 |
39 |
40 | {
41 | auth && !auth.uid &&
42 | }
43 | {
44 | profile.userType === "Admin" &&
45 | }
46 | {
47 | profile.userType === "Student" &&
48 | }
49 | {
50 | profile.userType === "Teacher" &&
51 | }
52 |
53 |
54 | )
55 | }
56 | }
57 |
58 | const mapStateToProps = (state) => {
59 | return {
60 | profile: state.firebase.profile,
61 | auth: state.firebase.auth,
62 | }
63 | }
64 |
65 |
66 | export default connect(mapStateToProps)(App);
67 |
--------------------------------------------------------------------------------
/src/Assets/Fest.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shashankbhat2/lms/f40dd5f6c42ac1a87dbf1b73ae5a8cf64c85c09e/src/Assets/Fest.png
--------------------------------------------------------------------------------
/src/Assets/Logo.svg:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/src/Assets/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shashankbhat2/lms/f40dd5f6c42ac1a87dbf1b73ae5a8cf64c85c09e/src/Assets/background.png
--------------------------------------------------------------------------------
/src/Assets/camera.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/Assets/hack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shashankbhat2/lms/f40dd5f6c42ac1a87dbf1b73ae5a8cf64c85c09e/src/Assets/hack.png
--------------------------------------------------------------------------------
/src/Auth/Login.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Row, Col, Container, Form, FormGroup, Label, Input, Button} from 'reactstrap'
3 | import '../App.css'
4 | import {Redirect} from 'react-router-dom'
5 | import {ReactComponent as Logo} from '../Assets/Logo.svg'
6 | import { Link } from 'react-router-dom'
7 | import {connect} from 'react-redux';
8 | import {signIn} from '../Store/actions/authActions';
9 | import Footer from '../Components/Footer/Footer'
10 | import CustomAlert from '../Components/Alert'
11 |
12 | class Login extends React.Component{
13 | constructor(props){
14 | super(props)
15 |
16 | this.state={
17 | input: {
18 | email: '',
19 | password: ''
20 | },
21 | errors: {}
22 | }
23 |
24 | }
25 |
26 | handleChange = (e) => {
27 | const input = this.state.input;
28 | const errors = this.state.errors;
29 | input[e.target.id] = e.target.value;
30 | errors[e.target.id] = '';
31 | this.setState({input});
32 | this.setState({errors})
33 | }
34 |
35 | handleSubmit = (e) => {
36 | e.preventDefault();
37 | if(this.validate()){
38 | this.props.signIn(this.state.input);
39 | }
40 | }
41 |
42 |
43 | validate(){
44 | let input = this.state.input;
45 | let errors = {};
46 | let isValid = true;
47 |
48 |
49 | if(!input["email"]){
50 | isValid = false;
51 | errors["email"] = "Please enter your email";
52 | }
53 |
54 | if(!input["password"]){
55 | isValid = false;
56 | errors["password"] = "Please enter the password";
57 | }
58 |
59 | this.setState({
60 | errors: errors
61 | })
62 |
63 | return isValid;
64 | }
65 |
66 |
67 | render(){
68 | const {auth, authError} = this.props;
69 | if(auth.uid) return ()
70 |
71 | return(
72 |
73 |
74 |
79 |
80 |
81 |
106 |
107 |
108 |
109 | )
110 | }
111 | }
112 |
113 | const mapStateToProps = (state) =>{
114 | return{
115 | auth : state.firebase.auth,
116 | authError: state.auth.authError,
117 | }
118 | }
119 |
120 | const mapDispatchToProps=(dispatch)=>{
121 | return{
122 | signIn : (creds) => dispatch(signIn(creds))
123 | }
124 | }
125 |
126 | export default connect(mapStateToProps,mapDispatchToProps)(Login);
127 |
--------------------------------------------------------------------------------
/src/Auth/Signup.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Row, Col, Container, Form, FormGroup, Label, Input, Button} from 'reactstrap'
3 | import '../App.css'
4 | import {ReactComponent as Logo} from '../Assets/Logo.svg'
5 | import { Link, Redirect } from 'react-router-dom'
6 | import {connect} from 'react-redux';
7 | import {signUp} from '../Store/actions/authActions';
8 | import { compose } from 'redux'
9 | import { firestoreConnect } from 'react-redux-firebase'
10 | import Footer from '../Components/Footer/Footer'
11 | import CustomAlert from '../Components/Alert'
12 |
13 | class Signup extends React.Component{
14 | constructor(props){
15 | super(props);
16 |
17 | this.state={
18 | input:{
19 | email: '',
20 | name: '',
21 | password: '',
22 | branch: 'CSE',
23 | type: 'Student',
24 | phone: '',
25 | semester: 'First',
26 | },
27 | errors: {}
28 | }
29 | }
30 |
31 | handleChange = (e) => {
32 | const input = this.state.input
33 | const errors = this.state.errors
34 | input[e.target.name] = e.target.value.trim();
35 | errors[e.target.name] = "";
36 | this.setState({input})
37 | this.setState({errors})
38 | }
39 |
40 | handleSubmit = (e) => {
41 | e.preventDefault();
42 | if(this.validate()){
43 | this.props.signUp(this.state.input);
44 | }
45 | }
46 |
47 | validate = () => {
48 | let input = this.state.input;
49 | let errors = {};
50 | let isValid = true;
51 |
52 | if(!input["email"]){
53 | isValid = false;
54 | errors["email"] = "Please enter your email address"
55 | }
56 |
57 | if (typeof input["email"] !== "undefined") {
58 |
59 | var pattern = new RegExp(/^(("[\w-\s]+")|([\w-]+(?:\.[\w-]+)*)|("[\w-\s]+")([\w-]+(?:\.[\w-]+)*))(@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$)|(@\[?((25[0-5]\.|2[0-4][0-9]\.|1[0-9]{2}\.|[0-9]{1,2}\.))((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){2}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\]?$)/i);
60 | if (!pattern.test(input["email"])) {
61 | isValid = false;
62 | errors["email"] = "Please enter valid email address.";
63 | }
64 | }
65 |
66 | if (!input["password"]) {
67 | isValid = false;
68 | errors["password"] = "Please enter your password.";
69 | }
70 |
71 | if (!input["name"]) {
72 | isValid = false;
73 | errors["name"] = "Please enter your name.";
74 | }
75 | if(!input["phone"]){
76 | isValid = false;
77 | errors["phone"] = "Please add your phone number"
78 | }
79 |
80 |
81 | this.setState({
82 | errors: errors
83 | })
84 |
85 | return isValid;
86 | }
87 |
88 |
89 |
90 | render(){
91 | const {auth, branches, semesters, authError} = this.props;
92 | if(auth.uid) return ()
93 | return(
94 |
95 |
96 |
101 |
102 |
103 |
207 |
208 |
209 |
210 | )
211 | }
212 | }
213 |
214 |
215 | const mapStateToProps = (state) => {
216 | return {
217 | auth: state.firebase.auth,
218 | profile: state.firebase.profile,
219 | branches: state.firestore.ordered.branches,
220 | semesters: state.firestore.ordered.semesters,
221 | authError: state.auth.authError,
222 | }
223 | }
224 |
225 |
226 | const mapDispatchToProps = (dispatch) => {
227 | return({
228 | signUp: (newUser) => {
229 | dispatch(signUp(newUser))
230 | }
231 | })
232 | }
233 |
234 |
235 |
236 | export default compose(connect(mapStateToProps, mapDispatchToProps),
237 | firestoreConnect([{collection: 'branches'}, {
238 | collection: 'semesters',
239 | doc: 'SemesterDoc',
240 | }]))(Signup);
241 |
242 |
--------------------------------------------------------------------------------
/src/Components/Alert/index.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import { Toast, ToastBody} from 'reactstrap';
3 |
4 |
5 | const CustomAlert = ({color, alert, authError}) => {
6 | const [visible, setVisible] = useState(true);
7 |
8 | useEffect(() => {
9 | const interval = setInterval(() => setVisible(false), 4000)
10 | return () => {
11 | clearInterval(interval)
12 | }
13 | }, [])
14 |
15 | return(
16 |
17 | { visible &&
18 |
19 | {alert}
20 |
21 |
22 | }
23 |
24 | )
25 | }
26 |
27 |
28 | export default CustomAlert;
--------------------------------------------------------------------------------
/src/Components/Cards/AssignmentCard.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button, CardBody, CardTitle, Card} from 'reactstrap'
3 |
4 | const AssignmentCard = ({assignment, handleAssignmentRemove, profile, uploadToggle, submissionsToggle, mySubmissionToggle}) => {
5 | const isStudent = profile.userType === "Student" ? true : false
6 |
7 | var today = new Date().getDate();
8 | var lastDate = new Date(assignment.lastDate).getDate();
9 | const deadline = today > lastDate ? true : false
10 |
11 | return(
12 |
13 |
14 |
15 | Question: {assignment.question}
16 | Teacher: {assignment.teacher}
17 | Branch: {assignment.branch}
18 | Last Date For Submission: {assignment.lastDate}
19 | Course: {assignment.course}
20 |
21 |
26 | {isStudent ? undefined :
27 |
30 | }
31 | {isStudent ? undefined :
32 |
35 | }
36 | {isStudent ? deadline ?
37 |
38 | Deadline Over
39 |
:
40 |
43 | :
44 | undefined
45 | }
46 | {isStudent ?
47 |
50 | :
51 | undefined
52 | }
53 |
54 |
55 | )
56 | }
57 |
58 |
59 | export default AssignmentCard;
--------------------------------------------------------------------------------
/src/Components/Cards/ClassCard.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Card, Button, CardTitle, CardText } from 'reactstrap'
3 |
4 | const ClassCard = ({teacherClass, handleClassRemove}) => {
5 | return(
6 |
7 | Subject: {teacherClass.course}
8 | Time: {teacherClass.time}
9 |
14 |
17 |
18 | )
19 | }
20 |
21 | export default ClassCard;
--------------------------------------------------------------------------------
/src/Components/Cards/CourseCard.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import {Card, CardBody, CardTitle, Button, Row, Col, CardSubtitle, Container} from 'reactstrap'
3 | import { connect } from 'react-redux'
4 | import { firestoreConnect } from 'react-redux-firebase'
5 | import { compose } from 'redux'
6 | import CustomModal from '../../Components/Modal'
7 | import { removeCourse } from '../../Store/actions/courseActions'
8 | import { NavLink } from 'react-router-dom'
9 |
10 |
11 |
12 | const CourseCard = ({courses, branch, sortedByBranch, removeCourse, admin}) => {
13 | const [isOpen, setIsOpen] = useState(false)
14 |
15 | const handleCourseRemoval = (course) => {
16 | removeCourse(course)
17 | }
18 |
19 |
20 | const toggle = () => setIsOpen(!isOpen)
21 |
22 | const sortedCourses = branch === "All Branches" ? courses : sortedByBranch;
23 |
24 | return(
25 |
26 |
27 | {sortedCourses && sortedCourses.map((c) =>
28 |
29 |
30 |
31 | {c.title}
32 | {c.teacher}
33 | {c.branch}
34 | {c.courseId}
35 |
40 | {admin ? : undefined}
41 |
42 |
43 |
44 |
45 | Are you sure?
46 |
47 |
48 |
49 |
50 |
51 | )}
52 |
53 |
54 | )
55 | }
56 |
57 |
58 |
59 | const mapStateToProps = (state) => {
60 | console.log(state)
61 | return{
62 | courses: state.firestore.ordered.courses,
63 | sortedByBranch: state.firestore.ordered.sortedByBranch
64 | }
65 | }
66 |
67 | const mapDispatchToProps = (dispatch) => {
68 | return({
69 | removeCourse: (course) => {
70 | dispatch(removeCourse(course))
71 | }
72 | })
73 | }
74 |
75 |
76 | export default compose(connect(mapStateToProps, mapDispatchToProps), firestoreConnect((props) => [
77 | {
78 | collection: 'courses',
79 | storeAs: 'courses'
80 | },
81 | {
82 | collection: 'courses',
83 | where: ['branch', '==', `${props.branch}`],
84 | storeAs: 'sortedByBranch'
85 | }
86 | ]))(CourseCard);
87 |
--------------------------------------------------------------------------------
/src/Components/Cards/ForumQuestionCard.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { connect } from 'react-redux';
3 | import {TrashCan24} from '@carbon/icons-react'
4 | import { Badge, Button, Card, CardTitle, Col, Input, ListGroup, ListGroupItem, Row } from 'reactstrap';
5 | import { addComment, removeQuestion, removeComment } from '../../Store/actions/forumActions';
6 |
7 |
8 | const ForumQuestionCard = ({question, profile, removeQuestion, removeComment, addComment}) => {
9 | let isTeacher = profile.userType === "Teacher" ? true : false;
10 | const [comment, setComment] = useState('')
11 |
12 | const handleRemove = () => {
13 | removeQuestion(question)
14 | }
15 |
16 | const handleComment = (question, comment, user) => {
17 | addComment(question, comment, user)
18 | }
19 |
20 | const handleCommentRemove = (question, comment, user) => {
21 | removeComment(question, comment, user)
22 | }
23 |
24 |
25 | return(
26 |
27 |
28 |
29 | {question.user}
30 | {question.question}
31 |
32 |
33 | {question.topic}
34 |
35 | {profile.name === question.user ?
36 | handleRemove(question)}/> : undefined}
37 |
38 |
39 | {isTeacher && }
51 |
52 |
{question.answers.length === 0 ? 'No Answers Yet' : 'Answers'}
53 | {question.answers.map((a) =>(
54 |
55 |
56 | {a.user}
57 | {a.comment}
58 | {
59 | profile.name === a.user ?
60 | handleCommentRemove(question, a.comment, a.user)}/>
61 | : undefined
62 | }
63 |
64 |
65 | ))}
66 |
67 |
68 |
69 | )
70 | }
71 |
72 | const mapStateToProps = (state) => {
73 | return{
74 | profile: state.firebase.profile
75 | }
76 | }
77 |
78 | const mapDispatchToProps = (dispatch) => {
79 | return{
80 | removeQuestion: (question) => {
81 | dispatch(removeQuestion(question))
82 | },
83 | addComment: (question, comment, user) => {
84 | dispatch(addComment(question, comment, user))
85 | },
86 | removeComment: (question, comment, user) => {
87 | dispatch(removeComment(question, comment, user))
88 | },
89 | }
90 | }
91 |
92 |
93 | export default connect(mapStateToProps, mapDispatchToProps)(ForumQuestionCard);
--------------------------------------------------------------------------------
/src/Components/Cards/ResourceCard.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button, Card, CardTitle, Col, Row} from 'reactstrap'
3 | import { removeResource } from '../../Store/actions/courseActions';
4 | import { connect } from 'react-redux'
5 |
6 |
7 |
8 | const ResourceCard = ({resources, course, profile, removeResource}) => {
9 |
10 | const resourceList = resources || [];
11 |
12 | const handleDelete = (course, title, url) => {
13 | removeResource(course,title, url)
14 | }
15 |
16 |
17 | return(
18 |
19 | {resourceList.map((r) => (
20 |
21 |
22 |
23 | {r.name}
24 |
29 | { profile.userType == "Student" ? null :
30 |
31 | }
32 |
33 |
34 |
35 | ))}
36 |
37 | )
38 | }
39 |
40 |
41 | const mapStateToProps = (state) => {
42 | return{
43 | profile: state.firebase.profile
44 | }
45 | }
46 |
47 |
48 |
49 | const mapDispatchToProps = (dispatch) => {
50 | return{
51 | removeResource: (course, title, url) => {
52 | dispatch(removeResource(course, title, url))
53 | }
54 | }
55 | }
56 |
57 | export default connect(mapStateToProps, mapDispatchToProps)(ResourceCard);
--------------------------------------------------------------------------------
/src/Components/Cards/VideoCard.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button, Card, CardTitle, Col, Row} from 'reactstrap'
3 | import { Player } from 'video-react'
4 | import { connect } from 'react-redux'
5 | import {removeVideo} from '../../Store/actions/courseActions'
6 |
7 |
8 | const VideoCard = ({videos, course, removeVideo, profile}) => {
9 |
10 | const videoList = videos || [];
11 |
12 | const handleDelete = (course, title, url) => {
13 | removeVideo(course,title, url)
14 | }
15 |
16 | return(
17 |
18 | {videoList.map((v) => (
19 |
20 |
21 |
22 |
23 |
24 |
25 | {v.name}
26 | { profile.userType == "Student" ? null :
27 |
28 | }
29 |
30 |
31 |
32 | ))}
33 |
34 | )
35 | }
36 |
37 |
38 | const mapStateToProps = (state) => {
39 | return{
40 | profile: state.firebase.profile
41 | }
42 | }
43 |
44 | const mapDispatchToProps = (dispatch) => {
45 | return{
46 | removeVideo: (course, title, url) => {
47 | dispatch(removeVideo(course, title, url))
48 | }
49 | }
50 | }
51 |
52 | export default connect(mapStateToProps, mapDispatchToProps) (VideoCard);
53 |
--------------------------------------------------------------------------------
/src/Components/Containers/AssignmentContainer.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { connect } from 'react-redux'
3 | import { firestoreConnect } from 'react-redux-firebase'
4 | import {Col} from 'reactstrap'
5 | import { compose } from 'redux'
6 | import CustomModal from '../Modal'
7 | import SubmissionsTable from '../Table/SubmissionsTable'
8 | import { removeAssignment } from '../../Store/actions/assignmentActions'
9 | import AssignmentCard from '../Cards/AssignmentCard'
10 | import UploadAssignment from '../Forms/UploadAssignment'
11 | import ViewSubmissionContainer from './ViewSubmissionContainer'
12 |
13 | const AssignmentContainer = ({teacher, removeAssignment, assignments,branch, sortedByBranch, sortedByTeacher, profile}) => {
14 | const branchWise = teacher ? sortedByTeacher : (branch === "All" ? assignments : sortedByBranch);
15 | let sortedAssignments = branchWise;
16 |
17 | const [isSubmissionsOpen, setIsSubmissionsOpen] = useState(false);
18 | const [isMySubmissionOpen, setMySubmissionOpen] = useState(false);
19 | const [isUploadOpen, setUploadOpen] = useState(false);
20 | const [selectedAssignment, setSelectedAssignment] = useState('')
21 |
22 | const handleAssignmentRemove = (assignment) => {
23 | removeAssignment(assignment)
24 | }
25 |
26 | const submissionsToggle = (a) =>
27 | {
28 | setSelectedAssignment(a)
29 | setIsSubmissionsOpen(!isSubmissionsOpen);
30 | }
31 | const uploadToggle = (a) => {
32 | setSelectedAssignment(a)
33 | setUploadOpen(!isUploadOpen);
34 | }
35 |
36 | const mySubmissionToggle = (a) => {
37 | setSelectedAssignment(a)
38 | setMySubmissionOpen(!isMySubmissionOpen)
39 | }
40 |
41 |
42 |
43 | return(
44 |
45 | {sortedAssignments && sortedAssignments.length !== 0 ? sortedAssignments.map((assignment) => (
46 |
47 |
48 |
49 | )) : (
50 |
51 |
You have created 0 Assignments
52 |
53 |
54 | )}
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | )
66 | }
67 |
68 |
69 | const mapStateToProps = (state) => {
70 | return{
71 | assignments: state.firestore.ordered.assignments,
72 | sortedByBranch: state.firestore.ordered.sortedByBranch,
73 | sortedByTeacher: state.firestore.ordered.sortedByTeacher,
74 | profile: state.firebase.profile
75 | }
76 | }
77 |
78 | const mapDispatchToProps = (dispatch) => {
79 | return({
80 | removeAssignment: (assignment) => {
81 | dispatch(removeAssignment(assignment))
82 | }
83 | })
84 | }
85 |
86 |
87 | export default compose(connect(mapStateToProps, mapDispatchToProps), firestoreConnect((props) => [
88 | {
89 | collection: 'assignments',
90 | },
91 | {
92 | collection: 'assignments',
93 | where: ['branch', '==', `${props.branch}`],
94 | storeAs: 'sortedByBranch'
95 | },
96 | {
97 | collection: 'assignments',
98 | where: ['teacher', '==', `${props.teacher}`],
99 | storeAs: 'sortedByTeacher'
100 | }
101 | ]))(AssignmentContainer)
--------------------------------------------------------------------------------
/src/Components/Containers/ClassesContainer.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { connect } from 'react-redux'
3 | import { firestoreConnect } from 'react-redux-firebase'
4 | import { Col } from 'reactstrap'
5 | import { compose } from 'redux'
6 | import { removeClass } from '../../Store/actions/classActions'
7 | import ClassCard from '../Cards/ClassCard'
8 |
9 | const ClassesContainer = ({classes,removeClass}) => {
10 | const teacherClasses = classes || []
11 |
12 | const handleClassRemove = (selectedClass) => {
13 | removeClass(selectedClass)
14 | }
15 |
16 | return(
17 |
18 | {teacherClasses && teacherClasses.length !== 0 ? teacherClasses.map((c) => (
19 |
20 |
21 |
22 | )) : (
23 |
24 |
You have no Classes
25 |
26 | )
27 | }
28 |
29 | )
30 | }
31 |
32 |
33 | const mapStateToProps = (state) => {
34 | return{
35 | classes: state.firestore.ordered.classes
36 | }
37 | }
38 |
39 | const mapDispatchToProps = (dispatch) => {
40 | return{
41 | removeClass: (selectedClass) => {
42 | dispatch(removeClass(selectedClass))
43 | }
44 | }
45 | }
46 |
47 |
48 | export default compose(connect(mapStateToProps, mapDispatchToProps), firestoreConnect((props)=>[
49 | {
50 | collection: 'classes',
51 | where: ['teacher', "==", `${props.teacher}`]
52 | }
53 | ]))(ClassesContainer);
--------------------------------------------------------------------------------
/src/Components/Containers/CourseContainer.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { connect } from 'react-redux'
3 | import { firestoreConnect } from 'react-redux-firebase'
4 | import { Button, Col, Container, Row } from 'reactstrap'
5 | import { compose } from 'redux'
6 | import ResourceCard from '../Cards/ResourceCard'
7 | import VideoCard from '../Cards/VideoCard'
8 | import AddResourcesForm from '../Forms/AddResourceForm'
9 | import AddVideoForm from '../Forms/AddVideoForm'
10 | import CustomModal from '../Modal'
11 |
12 |
13 | const dummy = {
14 | title: 'Test Course',
15 | branch: 'CSE',
16 | teacher: 'John Doe',
17 | courseId: ''
18 | }
19 |
20 |
21 | const CourseContainer = ({course, profile}) => {
22 |
23 | const currentCourse = course ? course[0] : dummy
24 | const isStudent = profile.userType === 'Student' ? true : false;
25 |
26 |
27 | const [isVideoFormOpen, setIsVideoFormOpen] = useState(false);
28 | const [isResourcesFormOpen, setIsResourcesFormOpen] = useState(false);
29 |
30 | const videoFormToggle = () => setIsVideoFormOpen(!isVideoFormOpen);
31 | const resourceFormToggle = () => setIsResourcesFormOpen(!isResourcesFormOpen);
32 |
33 | return(
34 |
35 |
36 |
37 | Course Title: {currentCourse.title || dummy.title}
38 | Branch: {currentCourse.branch || dummy.branch}
39 | Course Id: {currentCourse.courseId || dummy.courseId}
40 | {isStudent ? '' : }
41 | {isStudent ? '' :}
42 |
43 |
44 |
45 |
46 |
47 |
Course Videos
48 |
49 | {currentCourse.videos ?
50 |
53 | :
54 |
55 | }
56 |
57 |
58 |
59 |
60 |
61 |
Course Resources
62 |
63 |
64 | {currentCourse.videos ?
65 |
66 |
No Course Materials yet!
67 |
68 | : }
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | )
79 | }
80 |
81 | const mapStateToProps = (state) =>{
82 | return{
83 | profile: state.firebase.profile,
84 | course: state.firestore.ordered.course,
85 | }
86 | }
87 |
88 |
89 | export default compose(connect(mapStateToProps), firestoreConnect(
90 | (props) => [
91 | {
92 | collection: 'courses',
93 | where: ['title', '==', `${props.title}`],
94 | storeAs: 'course'
95 | }
96 | ]
97 | ))(CourseContainer);
--------------------------------------------------------------------------------
/src/Components/Containers/ViewSubmissionContainer.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import {Row, Container, Col} from 'reactstrap'
3 |
4 | const ViewSubmissionContainer = ({assignment, profile}) => {
5 | const [currentAssigment, setCurrentAssignment] = useState(assignment);
6 | const submission = currentAssigment.submissions.find((s) => s.name === profile.name)
7 | return(
8 |
9 | { submission ?
10 | <>
11 |
12 | Student Name: {submission.name}
13 |
14 |
15 | Submission Url: View
16 |
17 |
18 | Marks: {submission.marks}
19 |
20 | >
21 | :
22 | No Submission
}
23 |
24 | )
25 | }
26 |
27 | export default ViewSubmissionContainer;
--------------------------------------------------------------------------------
/src/Components/Footer/Footer.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const Footer = () => {
4 | return(
5 |
8 | )
9 | }
10 |
11 | export default Footer;
--------------------------------------------------------------------------------
/src/Components/Forms/AddAdminForm.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button, Col, Container, Form, Input, Label, Row } from 'reactstrap'
3 | import useForm from '../../Hooks/useForm'
4 |
5 | const AddAdminForm = () => {
6 | const handleAdminAdd = () => {
7 | fetch('https://us-central1-elearning-project-5423b.cloudfunctions.net/addAdmin', {
8 | method: 'POST',
9 | headers: {
10 | 'Accept': 'application/json',
11 | 'Content-Type': 'application/json'
12 | },
13 | body: JSON.stringify({
14 | email: inputs.email,
15 | name: inputs.name,
16 | password: inputs.password,
17 | phone: inputs.phone,
18 | })
19 | })
20 | .then((res) => (res.json()))
21 | .then((result) => {
22 | console.log(result)
23 | }).catch(err => {
24 | console.log(err)
25 | })
26 | }
27 |
28 |
29 | const { inputs, handleInputChange, handleSubmit} = useForm({name: '', email: '', phone: '', password:''}, handleAdminAdd)
30 |
31 | return(
32 |
63 | )
64 | }
65 |
66 |
67 |
68 | export default AddAdminForm;
--------------------------------------------------------------------------------
/src/Components/Forms/AddAssignmentForm.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { connect } from 'react-redux'
3 | import { firestoreConnect } from 'react-redux-firebase'
4 | import { Button, Col, Container, Form, Input, Label, Row } from 'reactstrap'
5 | import { compose } from 'redux'
6 | import useForm from '../../Hooks/useForm'
7 | import { addNewAssignment } from '../../Store/actions/assignmentActions'
8 |
9 |
10 | const AddAssignmentForm = ({branches, teachers, addNewAssignment, courses, profile}) => {
11 |
12 | const teacher = profile.userType === "Teacher" ? profile.name : ""
13 |
14 | const handleAssignment = () => {
15 | addNewAssignment(inputs)
16 | }
17 |
18 |
19 | const { inputs, handleInputChange, handleSubmit} = useForm({question:'', branch: "All", url: '', course: "Web Technology" , teacher: teacher, lastDate: ''}, handleAssignment)
20 |
21 | return(
22 |
68 | )
69 | }
70 |
71 |
72 | const mapStateToProps = (state) => {
73 | return{
74 | branches: state.firestore.ordered.branches,
75 | teachers: state.firestore.ordered.teachers,
76 | courses: state.firestore.ordered.courses,
77 | profile: state.firebase.profile
78 | }
79 | }
80 |
81 | const mapDispatchToProps = (dispatch) => {
82 | return({
83 | addNewAssignment: (assignment) => {
84 | dispatch(addNewAssignment(assignment))
85 | }
86 | })
87 | }
88 |
89 |
90 | export default compose(
91 | connect(mapStateToProps, mapDispatchToProps),
92 | firestoreConnect([
93 | {
94 | collection: 'branches'
95 | },
96 | {
97 | collection: 'users',
98 | where: ["userType", "==", "Teacher"],
99 | storeAs: 'teachers'
100 | },
101 | {
102 | collection: 'courses',
103 | }
104 | ])
105 | )(AddAssignmentForm);
106 |
--------------------------------------------------------------------------------
/src/Components/Forms/AddClassForm.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { connect } from 'react-redux'
3 | import { firestoreConnect } from 'react-redux-firebase'
4 | import { Button, Col, Container, Form, Input, Label, Row } from 'reactstrap'
5 | import { compose } from 'redux'
6 | import useForm from '../../Hooks/useForm'
7 | import {addClass} from '../../Store/actions/classActions'
8 |
9 | const AddClassForm = ({addClass, branches, courses, teacher}) => {
10 |
11 | const handleClass = () => {
12 | addClass(inputs)
13 | }
14 |
15 |
16 | const { inputs, handleInputChange, handleSubmit} = useForm({course:'', branch:'All', teacher: teacher.name, time: '', link: ''}, handleClass)
17 |
18 | return(
19 |
57 | )
58 | }
59 |
60 |
61 | const mapStateToProps = (state) => {
62 | return{
63 | courses: state.firestore.ordered.courses,
64 | branches: state.firestore.ordered.branches,
65 | teacher: state.firebase.profile
66 | }
67 | }
68 |
69 | const mapDispatchToProps = (dispatch) => {
70 | return({
71 | addClass: (newClass) => {
72 | dispatch(addClass(newClass))
73 | }
74 | })
75 | }
76 |
77 | export default compose(
78 | connect(mapStateToProps, mapDispatchToProps),
79 | firestoreConnect([
80 | {
81 | collection: 'courses'
82 | },
83 | {
84 | collection: 'branches'
85 | },
86 | ])
87 | )(AddClassForm);
--------------------------------------------------------------------------------
/src/Components/Forms/AddCourseForm.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { connect } from 'react-redux'
3 | import { firestoreConnect } from 'react-redux-firebase'
4 | import { Button, Col, Container, Form, Input, Label, Row } from 'reactstrap'
5 | import { compose } from 'redux'
6 | import useForm from '../../Hooks/useForm'
7 | import {addCourse} from '../../Store/actions/courseActions'
8 |
9 |
10 | const AddCourseForm = ({addCourse, branches}) => {
11 |
12 | const handleCourse = () => {
13 | addCourse(inputs)
14 | }
15 |
16 |
17 | const { inputs, handleInputChange, handleSubmit} = useForm({title:'', branch:'All', teacher: ''}, handleCourse)
18 |
19 | return(
20 |
46 | )
47 | }
48 |
49 |
50 | const mapStateToProps = (state) => {
51 | return{
52 | branches: state.firestore.ordered.branches
53 | }
54 | }
55 |
56 | const mapDispatchToProps = (dispatch) => {
57 | return({
58 | addCourse: (course) => {
59 | dispatch(addCourse(course))
60 | }
61 | })
62 | }
63 |
64 | export default compose(
65 | connect(mapStateToProps, mapDispatchToProps),
66 | firestoreConnect([
67 | {
68 | collection: 'branches'
69 | }
70 | ])
71 | )(AddCourseForm);
72 |
73 |
--------------------------------------------------------------------------------
/src/Components/Forms/AddNotificationForm.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { connect } from 'react-redux'
3 | import { Button, Col, Container, Form, Input, Label, Row } from 'reactstrap'
4 | import useForm from '../../Hooks/useForm'
5 | import { addNewNotification } from '../../Store/actions/notificationActions'
6 |
7 |
8 | const AddNotificationForm = ({addNewNotification}) => {
9 |
10 | const handleAddNotification = () => {
11 | addNewNotification(inputs)
12 | }
13 |
14 |
15 | const { inputs, handleInputChange, handleSubmit} = useForm({title:'', desc: ''}, handleAddNotification)
16 |
17 | return(
18 |
35 | )
36 | }
37 |
38 |
39 |
40 | const mapDispatchToProps = (dispatch) => {
41 | return({
42 | addNewNotification: (notification) => {
43 | dispatch(addNewNotification(notification))
44 | }
45 | })
46 | }
47 |
48 | export default connect(null, mapDispatchToProps)(AddNotificationForm);
49 |
--------------------------------------------------------------------------------
/src/Components/Forms/AddQuestionForm.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { connect } from 'react-redux'
3 | import { firestoreConnect } from 'react-redux-firebase'
4 | import { Button, Col, Container, Form, Input, Label, Row } from 'reactstrap'
5 | import { compose } from 'redux'
6 | import useForm from '../../Hooks/useForm'
7 | import { addQuestion } from '../../Store/actions/forumActions'
8 |
9 | const AddQuestionForm = ({addQuestion, courses, user}) => {
10 | const userName = user.name
11 | const handleClass = () => {
12 | addQuestion(inputs)
13 | }
14 |
15 |
16 | const { inputs, handleInputChange, handleSubmit} = useForm({topic: '', question: '', user: userName}, handleClass)
17 |
18 | return(
19 |
41 | )
42 | }
43 |
44 |
45 | const mapStateToProps = (state) => {
46 | return{
47 | courses: state.firestore.ordered.courses,
48 | user: state.firebase.profile
49 | }
50 | }
51 |
52 | const mapDispatchToProps = (dispatch) => {
53 | return({
54 | addQuestion: (newClass) => {
55 | dispatch(addQuestion(newClass))
56 | }
57 | })
58 | }
59 |
60 | export default compose(
61 | connect(mapStateToProps, mapDispatchToProps),
62 | firestoreConnect([
63 | {
64 | collection: 'courses'
65 | },
66 | ])
67 | )(AddQuestionForm);
--------------------------------------------------------------------------------
/src/Components/Forms/AddResourceForm.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { Container,Row, Col, Input, Label, Button, UncontrolledTooltip } from 'reactstrap'
3 | import {storage} from "../../config/fbConfig"
4 | import { addResource } from '../../Store/actions/courseActions'
5 | import { connect } from 'react-redux'
6 |
7 | const AddResourceForm = ({course, addResource}) => {
8 | const [name, setName] = useState('');
9 | const [file, setFile] = useState(undefined);
10 |
11 | const handleFile = (e) => {
12 | setFile(e.target.files[0])
13 | }
14 |
15 | const handleFileUpload = (file, course, name) => {
16 | const currentCourse = course;
17 | const newFile = file;
18 | const title = name;
19 | var metadata = {
20 | contentType: 'application/pdf',
21 | }
22 | const uploadTask = storage.ref(`/courseResources/${title}`).put(newFile, metadata);
23 | uploadTask.on("state_changed", console.log, console.error, () => {
24 | storage
25 | .ref("courseResources")
26 | .child(title)
27 | .getDownloadURL()
28 | .then((url) => {
29 | addResource(currentCourse, title, url)
30 | });
31 | });
32 | }
33 |
34 | return(
35 |
36 |
37 |
38 |
39 | setName(e.target.value)}>
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | PDF Files only
48 |
49 |
50 |
51 |
52 |
53 | )
54 | }
55 |
56 |
57 | const mapDispatchToProps = (dispatch) => {
58 | return({
59 | addResource: (course, title, url) => {
60 | dispatch(addResource(course, title, url))
61 | }
62 | })
63 | }
64 |
65 | export default connect(null, mapDispatchToProps)(AddResourceForm);
--------------------------------------------------------------------------------
/src/Components/Forms/AddVideoForm.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { Container,Row, Col, Input, Label, Button, UncontrolledTooltip } from 'reactstrap'
3 | import {storage} from "../../config/fbConfig"
4 | import { addNewVideo } from '../../Store/actions/courseActions'
5 | import { connect } from 'react-redux'
6 |
7 | const AddVideoForm = ({course, addNewVideo}) => {
8 | const [name, setName] = useState('');
9 | const [video, setVideo] = useState(undefined);
10 |
11 | const handleFile = (e) => {
12 | setVideo(e.target.files[0])
13 | }
14 |
15 | const handleFileUpload = (file, course, name) => {
16 | const currentCourse = course;
17 | const newVideo = file;
18 | const title = name;
19 | var metadata = {
20 | contentType: 'video/mp4',
21 | }
22 | const uploadTask = storage.ref(`/courseVideos/${title}`).put(newVideo, metadata);
23 | uploadTask.on("state_changed", console.log, console.error, () => {
24 | storage
25 | .ref("courseVideos")
26 | .child(title)
27 | .getDownloadURL()
28 | .then((url) => {
29 | addNewVideo(currentCourse, title, url)
30 | });
31 | });
32 | }
33 |
34 | return(
35 |
36 |
37 |
38 |
39 | setName(e.target.value)}>
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | Video Files
48 |
49 |
50 |
51 |
52 |
53 | )
54 | }
55 |
56 |
57 | const mapDispatchToProps = (dispatch) => {
58 | return({
59 | addNewVideo: (course, title, url) => {
60 | dispatch(addNewVideo(course, title, url))
61 | }
62 | })
63 | }
64 |
65 | export default connect(null, mapDispatchToProps)(AddVideoForm);
--------------------------------------------------------------------------------
/src/Components/Forms/EditStudentForm.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { connect } from 'react-redux'
3 | import { Button, Col, Container, Form, Input, Label, Row } from 'reactstrap'
4 | import { compose } from 'redux'
5 | import useForm from '../../Hooks/useForm'
6 | import { updateStudentInfo } from '../../Store/actions/studentActions'
7 | import CustomAlert from '../Alert'
8 |
9 | const EditStudentForm = ({student, updateStudentInfo, edited}) => {
10 |
11 | const updateStudent = () => {
12 | updateStudentInfo(inputs)
13 | }
14 |
15 | const {inputs, handleInputChange, handleSubmit} = useForm({
16 | id:student.id,
17 | name: student.name,
18 | email: student.email,
19 | father: student.father,
20 | mother: student.mother,
21 | srn:student.SRN,
22 | dob:student.dob,
23 | gender: student.gender,
24 | sslc:student.sslc,
25 | puc: student.puc,
26 | rank:student.rank,
27 | address: student.address,
28 | branch: student.Branch,
29 | semester: student.semester,
30 | }, updateStudent);
31 |
32 |
33 | return(
34 |
106 | )
107 | }
108 |
109 |
110 | const mapStateToProps = (state) => {
111 | console.log(state)
112 | return{
113 | edited: state.student.edited
114 | }
115 | }
116 |
117 |
118 | const mapDispatchToProps = (dispatch) => {
119 | return({
120 | updateStudentInfo: (student) => {
121 | dispatch(updateStudentInfo(student))
122 | }
123 | })
124 | }
125 |
126 | export default compose(connect(mapStateToProps, mapDispatchToProps))(EditStudentForm);
127 |
128 |
129 |
--------------------------------------------------------------------------------
/src/Components/Forms/EditTeacherForm.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { connect } from 'react-redux'
3 | import { Button, Col, Container, Form, Input, Label, Row } from 'reactstrap'
4 | import { compose } from 'redux'
5 | import useForm from '../../Hooks/useForm'
6 | import { updateTeacherInfo } from '../../Store/actions/teacherActions'
7 |
8 | const EditTeacherForm = ({teacher, updateTeacherInfo}) => {
9 |
10 | const updateTeacher = () => {
11 | updateTeacherInfo(inputs)
12 | }
13 |
14 | const {inputs, handleInputChange, handleSubmit} = useForm({
15 | id:teacher.id,
16 | name: teacher.name,
17 | email: teacher.email,
18 | father: teacher.father,
19 | mother: teacher.mother,
20 | srn:teacher.SRN,
21 | gender: teacher.gender,
22 | dob:teacher.dob,
23 | sslc:teacher.sslc,
24 | puc: teacher.puc,
25 | bachelor: teacher.bachelor,
26 | master: teacher.master,
27 | address: teacher.address,
28 | branch: teacher.Branch
29 | }, updateTeacher);
30 |
31 |
32 | return(
33 |
103 | )
104 | }
105 |
106 |
107 | const mapStateToProps = (state) => {
108 | console.log(state)
109 | return{
110 | edited: state.student.edited
111 | }
112 | }
113 |
114 |
115 | const mapDispatchToProps = (dispatch) => {
116 | return({
117 | updateTeacherInfo: (teacher) => {
118 | dispatch(updateTeacherInfo(teacher))
119 | }
120 | })
121 | }
122 |
123 | export default compose(connect(mapStateToProps, mapDispatchToProps))(EditTeacherForm);
124 |
125 |
126 |
--------------------------------------------------------------------------------
/src/Components/Forms/UploadAssignment.js:
--------------------------------------------------------------------------------
1 | import React,{useState} from 'react'
2 | import { Container,Row, Col, Input, Label, Button} from 'reactstrap'
3 | import {storage} from "../../config/fbConfig"
4 | import { connect } from 'react-redux'
5 | import { addNewSubmission } from '../../Store/actions/assignmentActions'
6 |
7 | const UploadAssignmentForm = ({addNewSubmission, assignment, profile}) => {
8 | const [currentAssigment, setCurrentAssignment] = useState(assignment)
9 | const student = profile.name;
10 | const srn = profile.SRN;
11 | console.log(srn)
12 | const [file, setFile] = useState(undefined);
13 |
14 | const handleFile = (e) => {
15 | setFile(e.target.files[0])
16 | }
17 |
18 | const handleFileUpload = (file, student, assignment, srn) => {
19 | const newFile = file;
20 | const title = assignment.question;
21 | var metadata = {
22 | contentType: 'application/pdf',
23 | }
24 | const uploadTask = storage.ref(`/assignmentSubmissions/${title}`).put(newFile, metadata);
25 | uploadTask.on("state_changed", console.log, console.error, () => {
26 | storage
27 | .ref("assignmentSubmissions")
28 | .child(title)
29 | .getDownloadURL()
30 | .then((url) => {
31 | addNewSubmission(assignment, student, url, srn)
32 | });
33 | });
34 | }
35 |
36 | return(
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | )
57 | }
58 |
59 |
60 | const mapDispatchToProps = (dispatch) => {
61 | return({
62 | addNewSubmission: (assignment, student, url, srn) => {
63 | dispatch(addNewSubmission(assignment, student, url, srn))
64 | }
65 | })
66 | }
67 |
68 | export default connect(null, mapDispatchToProps)(UploadAssignmentForm);
--------------------------------------------------------------------------------
/src/Components/Info/Info.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { connect } from 'react-redux'
3 | import { Card, CardImg, Col, Row, Button} from 'reactstrap'
4 | import { compose } from 'redux'
5 | import { firestoreConnect } from 'react-redux-firebase'
6 | import Camera from '../../Assets/camera.svg'
7 | import {setStudentSuspended, updateStudentDisplayPic} from '../../Store/actions/studentActions'
8 | import {storage} from '../../config/fbConfig'
9 | import CustomModal from '../Modal/';
10 | import EditStudentForm from '../Forms/EditStudentForm'
11 | import CustomAlert from '../Alert/'
12 |
13 | const dummy = {
14 | 'img': 'https://i.ibb.co/wd8cRVZ/img-person-placeholder.jpg',
15 | 'name' : 'John Doe',
16 | 'SRN' : 'dsu1200'
17 | }
18 |
19 | const InfoContainer = ({student,setStudentSuspended, updateStudentDisplayPic}) => {
20 | const [isOpen, setIsOpen] = useState(false);
21 |
22 | const currentStudent = student ? student[0] : dummy
23 |
24 | const toggle = () => setIsOpen(!isOpen);
25 |
26 | const handleSuspend = (student) => {
27 | setStudentSuspended(student)
28 | }
29 |
30 | const handleUpload = (file, currentStudent) => {
31 | const profile = file;
32 | const name = currentStudent.name;
33 | var metadata = {
34 | contentType: 'image/jpeg'
35 | }
36 | const uploadImage = storage.ref(`userImages/${name}`).put(profile, metadata)
37 | uploadImage.on('state_changed',
38 | () => {
39 | storage.ref(`userImages/${name}`).getDownloadURL().then(
40 | url => {
41 | updateStudentDisplayPic(currentStudent,url)
42 | },
43 | )
44 | },
45 | )
46 | }
47 |
48 | return(
49 | <>
50 |
51 |
52 |
53 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | Basic Info
68 |
69 |
70 | Student Name: {currentStudent.name}
71 |
72 |
73 | SRN: {currentStudent.SRN}
74 |
75 |
76 | Gender: {currentStudent.gender}
77 |
78 |
79 |
80 |
81 | Branch: {currentStudent.Branch}
82 |
83 |
84 | Semester: {currentStudent.semester}
85 |
86 |
87 |
88 |
89 | Mother's Name: {currentStudent.mother || ''}
90 |
91 |
92 | Father's Name: {currentStudent.father || ''}
93 |
94 |
95 |
96 |
97 | DOB: {currentStudent.dob || ''}
98 |
99 |
100 | Phone: +91 {currentStudent.phone}
101 |
102 |
103 |
104 |
105 | Address: {currentStudent.address || ''}
106 |
107 |
108 |
109 |
110 | Educational Info
111 |
112 |
113 | SSLC: {currentStudent.sslc || ''}
114 |
115 |
116 | PUC: {currentStudent.puc || ''}
117 |
118 |
119 |
120 |
121 | Entrance Exam Rank: {currentStudent.rank || ''}
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | >
132 | )
133 | }
134 |
135 | const mapStateToProps = (state) => {
136 | return{
137 | student: state.firestore.ordered.users,
138 | }
139 | }
140 |
141 | const mapDispatchToProps = (dispatch) => {
142 | return({
143 | setStudentSuspended: (student) => {
144 | dispatch(setStudentSuspended(student))
145 | },
146 | updateStudentDisplayPic: (student, url) => {
147 | dispatch(updateStudentDisplayPic(student,url))
148 | }
149 | })
150 | }
151 |
152 |
153 |
154 | export default compose(connect(mapStateToProps, mapDispatchToProps), firestoreConnect(
155 | (props) => [
156 | {
157 | collection: 'users',
158 | where: ['name','==', `${props.name}`]
159 | }
160 | ]
161 | ))(InfoContainer);
162 |
--------------------------------------------------------------------------------
/src/Components/Info/TeacherInfo.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { connect } from 'react-redux'
3 | import { Card, CardImg, Col, Row, Button} from 'reactstrap'
4 | import { compose } from 'redux'
5 | import { firestoreConnect } from 'react-redux-firebase'
6 | import Camera from '../../Assets/camera.svg'
7 | import {updateTeacherDisplayPic} from '../../Store/actions/teacherActions'
8 | import {storage} from '../../config/fbConfig'
9 | import CustomModal from '../Modal/';
10 | import EditTeacherForm from '../Forms/EditTeacherForm'
11 |
12 | const dummy = {
13 | 'img': 'https://i.ibb.co/wd8cRVZ/img-person-placeholder.jpg',
14 | 'name' : 'John Doe',
15 | 'SRN' : 'dsu1200'
16 | }
17 |
18 | const TeacherInfo = ({teacher,updateTeacherDisplayPic}) => {
19 | const [isOpen, setIsOpen] = useState(false);
20 |
21 | const currentTeacher = teacher ? teacher[0] : dummy
22 |
23 | const toggle = () => setIsOpen(!isOpen);
24 |
25 | const handleUpload = (file, currentTeacher) => {
26 | const profile = file;
27 | const name = currentTeacher.name;
28 | var metadata = {
29 | contentType: 'image/jpeg'
30 | }
31 | const uploadImage = storage.ref(`userImages/${name}`).put(profile, metadata)
32 | uploadImage.on('state_changed',
33 | () => {
34 | storage.ref(`userImages/${name}`).getDownloadURL().then(
35 | url => {
36 | updateTeacherDisplayPic(currentTeacher,url)
37 | },
38 | )
39 | },
40 | )
41 | }
42 |
43 | return(
44 | <>
45 |
46 |
47 |
48 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | Basic Info
62 |
63 |
64 | Student Name: {currentTeacher.name}
65 |
66 |
67 | SRN: {currentTeacher.SRN}
68 |
69 |
70 |
71 |
72 | Gender: {currentTeacher.gender}
73 |
74 |
75 | Branch: {currentTeacher.Branch}
76 |
77 |
78 |
79 |
80 | Mother's Name: {currentTeacher.mother || ''}
81 |
82 |
83 | Father's Name: {currentTeacher.father || ''}
84 |
85 |
86 |
87 |
88 | DOB: {currentTeacher.dob || ''}
89 |
90 |
91 | Phone: +91 {currentTeacher.phone}
92 |
93 |
94 |
95 |
96 | Address: {currentTeacher.address || ''}
97 |
98 |
99 |
100 |
101 | Educational Info
102 |
103 |
104 | SSLC: {currentTeacher.sslc || ''}
105 |
106 |
107 | PUC: {currentTeacher.puc || ''}
108 |
109 |
110 |
111 |
112 | Bachelor's Degree: {currentTeacher.bachelor || ''}
113 |
114 |
115 | Master's Degree: {currentTeacher.master || ''}
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 | >
126 | )
127 | }
128 |
129 | const mapStateToProps = (state) => {
130 | return{
131 | teacher: state.firestore.ordered.users,
132 | }
133 | }
134 |
135 | const mapDispatchToProps = (dispatch) => {
136 | return({
137 | updateTeacherDisplayPic: (student, url) => {
138 | dispatch(updateTeacherDisplayPic(student,url))
139 | }
140 | })
141 | }
142 |
143 |
144 |
145 | export default compose(connect(mapStateToProps, mapDispatchToProps), firestoreConnect(
146 | (props) => [
147 | {
148 | collection: 'users',
149 | where: ['name','==', `${props.name}`]
150 | }
151 | ]
152 | ))(TeacherInfo);
--------------------------------------------------------------------------------
/src/Components/Modal/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Modal, ModalBody, ModalHeader, ModalFooter, Button} from 'reactstrap'
3 |
4 | const CustomModal = ({modal, toggle, title, close, children}) => {
5 | return(
6 |
7 | {title}
8 |
9 | {children}
10 |
11 |
12 |
13 |
14 |
15 | )
16 | }
17 |
18 | export default CustomModal;
--------------------------------------------------------------------------------
/src/Components/Navbar/Navbar.js:
--------------------------------------------------------------------------------
1 | import React, {useState} from 'react'
2 | import {
3 | Collapse,
4 | Navbar,
5 | NavbarToggler,
6 | NavbarBrand,
7 | Nav,
8 | NavItem,
9 | NavLink,
10 | UncontrolledDropdown,
11 | DropdownToggle,
12 | DropdownMenu,
13 | DropdownItem
14 | } from 'reactstrap';
15 | import {Link} from 'react-router-dom';
16 | import {connect} from 'react-redux';
17 | import {signOut} from '../../Store/actions/authActions';
18 |
19 |
20 | const CustomNavbar = ({links, currentUser, signOut}) => {
21 | const [isOpen, setIsOpen] = useState(false);
22 | const toggle = () => setIsOpen(!isOpen);
23 |
24 | return(
25 |
26 |
27 | Acadonline
28 |
29 |
30 |
38 | {
39 | currentUser ?
40 |
41 |
42 | {currentUser.name ? currentUser.name : ''}
43 |
44 |
45 | Logout
46 |
47 |
48 | :
49 | ''
50 | }
51 |
52 |
53 |
54 | )
55 | }
56 |
57 | const mapDispatchToProps = (dispatch) =>{
58 | return{
59 | signOut : () => dispatch(signOut())
60 | }
61 | }
62 |
63 | export default connect(null,mapDispatchToProps)(CustomNavbar);
--------------------------------------------------------------------------------
/src/Components/Notification/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { Button, ListGroup, ListGroupItem, ListGroupItemHeading, ListGroupItemText } from 'reactstrap';
3 | import AddNotificationForm from '../Forms/AddNotificationForm';
4 | import CustomModal from '../Modal/index'
5 |
6 | const Notification = ({notifications, profile}) => {
7 |
8 | const [formOpen, setFormOpen] = useState(false);
9 |
10 | const formToggle = () => setFormOpen(!formOpen);
11 |
12 | return(
13 |
14 |
15 |
16 | Notifications
17 |
18 | {notifications ? notifications.map((i) => (
19 |
20 | {i.title}
21 |
22 | {i.desc}
23 |
24 |
25 | ))
26 | : Loading Notifications
}
27 | {
28 | profile.userType === "Admin" ?
29 |
30 |
31 |
32 | :
33 | undefined
34 | }
35 |
36 |
37 |
38 |
39 |
40 | )
41 | }
42 |
43 | export default Notification;
--------------------------------------------------------------------------------
/src/Components/Slider/index.js:
--------------------------------------------------------------------------------
1 | import React,{useState} from 'react'
2 | import {
3 | Carousel,
4 | CarouselItem,
5 | CarouselControl,
6 | CarouselIndicators,
7 | CarouselCaption
8 | } from 'reactstrap';
9 |
10 |
11 | const items = [
12 | {
13 | src:'https://i.ibb.co/YTW8Lmd/Fest.png',
14 | caption: 'Cultfest 2021'
15 | },
16 | {
17 | src:'https://i.ibb.co/vPGtxFk/hack.png',
18 | caption: 'HackTommorrow'
19 | },
20 | ];
21 |
22 |
23 |
24 |
25 | const Slider = () => {
26 | const [activeIndex, setActiveIndex] = useState(0);
27 | const [animating, setAnimating] = useState(false);
28 |
29 | const next = () => {
30 | if (animating) return;
31 | const nextIndex = activeIndex === items.length - 1 ? 0 : activeIndex + 1;
32 | setActiveIndex(nextIndex);
33 | }
34 |
35 | const previous = () => {
36 | if (animating) return;
37 | const nextIndex = activeIndex === 0 ? items.length - 1 : activeIndex - 1;
38 | setActiveIndex(nextIndex);
39 | }
40 |
41 | const goToIndex = (newIndex) => {
42 | if (animating) return;
43 | setActiveIndex(newIndex);
44 | }
45 |
46 | const slides = items.map((item) => {
47 | return (
48 | setAnimating(true)}
50 | onExited={() => setAnimating(false)}
51 | key={item.src}
52 | className="carousel"
53 | >
54 |
55 |
56 |
57 | );
58 | });
59 |
60 | return (
61 |
66 |
67 | {slides}
68 |
69 |
70 |
71 | );
72 | }
73 |
74 | export default Slider;
--------------------------------------------------------------------------------
/src/Components/Table/AdminTable.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { firestoreConnect } from 'react-redux-firebase'
3 | import {connect} from 'react-redux'
4 | import { compose } from 'redux'
5 | import {Table} from 'reactstrap'
6 |
7 | const AdminTable = ({admins}) => {
8 |
9 | return(
10 |
11 |
12 |
13 |
14 | Name |
15 | Email |
16 | Phone |
17 |
18 |
19 |
20 | {admins && admins.map((admin, i)=> (
21 |
22 |
23 | {admin.name}
24 | |
25 | {admin.email} |
26 | {admin.phone} |
27 |
28 | ))}
29 |
30 |
31 |
32 | )
33 | }
34 |
35 |
36 | const mapStateToProps = (state) => {
37 | console.log(state)
38 | return{
39 | admins: state.firestore.ordered.users || [],
40 | }
41 | }
42 |
43 |
44 | export default compose(connect(mapStateToProps), firestoreConnect(
45 | [
46 | {
47 | collection: 'users',
48 | where: [['userType', '==', 'Admin']],
49 | },
50 | ]))(AdminTable);
--------------------------------------------------------------------------------
/src/Components/Table/StudentTable.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import { firestoreConnect } from 'react-redux-firebase'
3 | import {connect} from 'react-redux'
4 | import { compose } from 'redux'
5 | import {Button, Form, Input, Table} from 'reactstrap'
6 | import { NavLink } from 'react-router-dom'
7 | import {setStudentSuspended} from '../../Store/actions/studentActions'
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | const StudentTable = ({students, sortedByBranch, branch, setStudentSuspended}) => {
16 | const branchWise = branch === 'All' ? students : sortedByBranch;
17 | let studentData = branchWise;
18 |
19 |
20 | const handleSuspend = (student) => {
21 | setStudentSuspended(student)
22 | }
23 |
24 | return(
25 |
26 |
27 |
28 |
29 | Name |
30 | Branch |
31 | SRN |
32 | Semester |
33 | Email |
34 | Phone |
35 | Suspend Student |
36 |
37 |
38 |
39 | {studentData && studentData.map((student)=> (
40 |
41 |
42 |
43 | {student.name}
44 | |
45 | {student.Branch} |
46 | {student.SRN} |
47 | {student.semester} |
48 | {student.email} |
49 | {student.phone} |
50 |
51 |
52 | |
53 |
54 | ))}
55 |
56 |
57 |
58 | )
59 | }
60 |
61 |
62 | const mapStateToProps = (state) => {
63 | console.log(state)
64 | return{
65 | students: state.firestore.ordered.users || [],
66 | sortedByBranch: state.firestore.ordered.sortedByBranch || [],
67 | }
68 | }
69 |
70 | const mapDispatchToProps = (dispatch) => {
71 | return({
72 | setStudentSuspended: (student) => {
73 | dispatch(setStudentSuspended(student))
74 | }
75 | })
76 | }
77 |
78 |
79 |
80 |
81 |
82 | export default compose(connect(mapStateToProps, mapDispatchToProps), firestoreConnect((props) =>
83 | [
84 | {
85 | collection: 'users',
86 | where: [['userType', '==', 'Student']],
87 | },
88 | {
89 | collection: 'users',
90 | where: [['userType', '==', 'Student'], ['Branch','==',`${props.branch}`]],
91 | storeAs: 'sortedByBranch'
92 | },
93 | ]))(StudentTable);
--------------------------------------------------------------------------------
/src/Components/Table/SubmissionsTable.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { connect } from 'react-redux';
3 | import { Button, Input, Table } from 'reactstrap';
4 | import { addMarks } from '../../Store/actions/assignmentActions';
5 |
6 | const SubmissionsTable = ({assignment, addMarks}) => {
7 | const [currentAssigment, setCurrentAssignment] = useState(assignment)
8 | const [marks, setMarks] = useState('')
9 | const handleMarks = (assignment, submission, marks) => {
10 | addMarks(assignment, submission, marks)
11 | }
12 |
13 | return(
14 |
15 |
50 |
51 | )
52 | }
53 |
54 | const mapDispatchToProps = (dispatch) => {
55 | return({
56 | addMarks: (assignment, submission, marks) => {
57 | dispatch(addMarks(assignment, submission, marks))
58 | }
59 | })
60 | }
61 | export default connect(null, mapDispatchToProps)(SubmissionsTable);
--------------------------------------------------------------------------------
/src/Components/Table/TeacherTable.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { firestoreConnect } from 'react-redux-firebase'
3 | import {connect} from 'react-redux'
4 | import { compose } from 'redux'
5 | import {Table} from 'reactstrap'
6 | import { NavLink } from 'react-router-dom'
7 |
8 |
9 | const TeacherTable = ({teachers, sortedByBranch, branch}) => {
10 |
11 | const branchWise = branch === 'All' ? teachers : sortedByBranch;
12 | let teacherData = branchWise;
13 |
14 | return(
15 |
16 |
17 |
18 |
19 | Name |
20 | SRN |
21 | Branch |
22 | Semester |
23 | Email |
24 | Phone |
25 |
26 |
27 |
28 | {teacherData && teacherData.map((teacher)=> (
29 |
30 |
31 |
32 | {teacher.name}
33 |
34 | |
35 | {teacher.Branch} |
36 | {teacher.SRN} |
37 | {teacher.semester} |
38 | {teacher.email} |
39 | {teacher.phone} |
40 |
41 | ))}
42 |
43 |
44 |
45 | )
46 | }
47 |
48 |
49 | const mapStateToProps = (state) => {
50 | console.log(state)
51 | return{
52 | teachers: state.firestore.ordered.users || [],
53 | sortedByBranch: state.firestore.ordered.sortedByBranch || [],
54 | }
55 | }
56 |
57 |
58 | export default compose(connect(mapStateToProps), firestoreConnect((props) =>
59 | [
60 | {
61 | collection: 'users',
62 | where: [['userType', '==', 'Teacher']],
63 | },
64 | {
65 | collection: 'users',
66 | where: [['userType', '==', 'Teacher'], ['Branch','==',`${props.branch}`]],
67 | storeAs: 'sortedByBranch'
68 | },
69 | ]))(TeacherTable);
--------------------------------------------------------------------------------
/src/Dashboards/admin/AdminDashboard.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { connect } from 'react-redux';
3 | import { Redirect, Route, Switch } from 'react-router';
4 | import Footer from '../../Components/Footer/Footer';
5 | import Overview from './pages/Overview'
6 | import Students from './pages/Students'
7 | import Student from './pages/Student';
8 | import CustomAlert from '../../Components/Alert';
9 | import Courses from './pages/Courses';
10 | import Course from './pages/Course';
11 | import Teachers from './pages/Teachers';
12 | import Assignments from './pages/Assignments';
13 | import Admins from './pages/Admins';
14 | import Teacher from './pages/Teacher';
15 |
16 |
17 |
18 |
19 | const AdminDashboard = ({auth, upload, authSuccess}) => {
20 |
21 | if(!auth.uid) return
22 |
23 |
24 | return(
25 |
26 | {authSuccess && }
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | )
41 | }
42 |
43 |
44 | const mapStateToProps = (state) => {
45 | return {
46 | auth: state.firebase.auth,
47 | authSuccess: state.auth.authSuccess,
48 | profile: state.firebase.profile,
49 | }
50 | }
51 |
52 | export default connect(mapStateToProps)(AdminDashboard);
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/src/Dashboards/admin/pages/Admins.js:
--------------------------------------------------------------------------------
1 | import React, {useState} from 'react'
2 | import { Container, Button,Row, Col} from 'reactstrap'
3 | import AddAdminForm from '../../../Components/Forms/AddAdminForm'
4 | import CustomModal from '../../../Components/Modal'
5 | import AdminTable from '../../../Components/Table/AdminTable'
6 |
7 | const Admins = () => {
8 | const [isOpen, setIsOpen] = useState(false)
9 |
10 | const toggle = () => setIsOpen(!isOpen);
11 |
12 | return(
13 |
14 | Admins
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | )
28 | }
29 |
30 |
31 | export default Admins
--------------------------------------------------------------------------------
/src/Dashboards/admin/pages/Assignments.js:
--------------------------------------------------------------------------------
1 | import React,{useState} from 'react'
2 | import { connect } from 'react-redux'
3 | import { firestoreConnect } from 'react-redux-firebase'
4 | import { compose } from 'redux'
5 | import { Container, Input,Row, Col, Button} from 'reactstrap'
6 | import CustomModal from '../../../Components/Modal/'
7 | import AssignmentContainer from '../../../Components/Containers/AssignmentContainer'
8 | import AddAssignmentForm from '../../../Components/Forms/AddAssignmentForm'
9 |
10 |
11 | const Assignments = ({branches, profile}) => {
12 | const [selectedBranch, setSelectedBranch] = useState('All');
13 | const [isOpen, setIsOpen] = useState(false)
14 |
15 | const student = profile.userType === 'Student' ? profile : false;
16 |
17 | const toggle = () => setIsOpen(!isOpen);
18 |
19 | const handleBranch = (e) => {
20 | setSelectedBranch(e.target.value)
21 | }
22 |
23 | return(
24 |
25 | Assignments
26 |
27 | Branch: {selectedBranch}
28 |
29 |
30 |
31 |
32 |
33 | Select Branch
34 |
35 |
36 |
37 |
38 | {branches && branches.map(branch => (
39 |
40 | ))}
41 |
42 |
43 |
44 | {student ? undefined : }
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | )
56 | }
57 |
58 |
59 | const mapStateToProps = (state) => {
60 | return{
61 | branches: state.firestore.ordered.branches,
62 | profile: state.firebase.profile
63 | }
64 | }
65 |
66 |
67 |
68 | export default compose(connect(mapStateToProps), firestoreConnect([
69 | {
70 | collection: 'branches'
71 | }
72 | ])) (Assignments);
--------------------------------------------------------------------------------
/src/Dashboards/admin/pages/Course.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useParams } from 'react-router'
3 | import { Container } from 'reactstrap'
4 | import CourseContainer from '../../../Components/Containers/CourseContainer';
5 |
6 |
7 | const Course = () => {
8 | const {course} = useParams();
9 |
10 | return(
11 |
12 | Course
13 |
14 |
15 | )
16 | }
17 |
18 |
19 | export default Course;
--------------------------------------------------------------------------------
/src/Dashboards/admin/pages/Courses.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { connect } from 'react-redux'
3 | import { firestoreConnect } from 'react-redux-firebase'
4 | import { compose } from 'redux'
5 | import {Container, Row, Col, Input, Button} from 'reactstrap'
6 | import CourseCard from '../../../Components/Cards/CourseCard'
7 | import CustomModal from '../../../Components/Modal'
8 | import AddCourseForm from '../../../Components/Forms/AddCourseForm'
9 |
10 | const Courses = ({branches, profile}) => {
11 | const [branch, setBranch] = useState('All Branches')
12 |
13 | const admin = profile.userType === "Admin" ? true : false;
14 |
15 | const [isOpen, setIsOpen] = useState(false);
16 |
17 | const toggle = () => setIsOpen(!isOpen);
18 |
19 |
20 | const handleBranch = (e) => {
21 | setBranch(e.target.value)
22 | }
23 |
24 |
25 | return(
26 |
27 | Courses
28 |
29 |
30 | Branch: {branch}
31 |
32 |
33 |
34 | Select Branch
35 |
36 |
37 |
38 |
39 | {branches && branches.map(branch => (
40 |
41 | ))}
42 |
43 |
44 |
45 | {admin ? : undefined}
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | )
55 | }
56 |
57 | const mapStateToProps = (state) => {
58 | return{
59 | branches: state.firestore.ordered.branches,
60 | profile: state.firebase.profile
61 | }
62 | }
63 |
64 | export default compose(connect(mapStateToProps), firestoreConnect([
65 | {
66 | collection: 'branches'
67 | },
68 | ])) (Courses);
--------------------------------------------------------------------------------
/src/Dashboards/admin/pages/Overview.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { connect } from 'react-redux';
3 | import { firestoreConnect } from 'react-redux-firebase';
4 | import { Card, Row, Container, Col } from 'reactstrap';
5 | import { compose } from 'redux';
6 | import Notification from '../../../Components/Notification';
7 | import Slider from '../../../Components/Slider';
8 |
9 | // const notifications = [
10 | // {
11 | // id:1,
12 | // title: 'ESA Schedule',
13 | // desc: 'ESA for Btech & Mtech scheduled from May 10th - 25th'
14 | // },
15 | // {
16 | // id:2,
17 | // title: 'Hacktomorrow',
18 | // desc: 'CSE Dept. Presents Hacktomorrow'
19 | // },
20 | // {
21 | // id:3,
22 | // title: 'CultFest2021',
23 | // desc: 'Inter Dept. Cultural festival'
24 | // },
25 |
26 | // ]
27 |
28 |
29 | const Overview = ({profile, notifications}) => {
30 | return(
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | Welcome
40 | {profile.name}
41 |
42 |
43 |
44 |
45 | )
46 | }
47 |
48 | const mapStateToProps = (state) => {
49 | console.log(state)
50 | return {
51 | profile: state.firebase.profile,
52 | notifications: state.firestore.ordered.notifications
53 | }
54 | }
55 |
56 | export default compose(connect(mapStateToProps), firestoreConnect([
57 | {
58 | collection: 'notifications',
59 | }
60 | ]))(Overview);
61 |
--------------------------------------------------------------------------------
/src/Dashboards/admin/pages/Student.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useParams } from 'react-router'
3 | import { Container } from 'reactstrap'
4 | import InfoContainer from '../../../Components/Info/Info'
5 |
6 |
7 | const Student = () => {
8 |
9 | const {student} = useParams();
10 |
11 |
12 | return(
13 |
14 | Student Details
15 |
16 |
17 | )
18 | }
19 |
20 |
21 | export default Student;
--------------------------------------------------------------------------------
/src/Dashboards/admin/pages/Students.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { firestoreConnect } from 'react-redux-firebase'
3 | import { Container, Input,Row, Col} from 'reactstrap'
4 | import { compose } from 'redux'
5 | import {connect} from 'react-redux';
6 | import StudentTable from '../../../Components/Table/StudentTable'
7 |
8 |
9 |
10 | const Students = ({branches}) => {
11 | const [selectedBranch, setSelectedBranch] = useState('All');
12 |
13 | const handleBranch = (e) => {
14 | setSelectedBranch(e.target.value)
15 | }
16 |
17 |
18 | return(
19 |
20 | Students
21 |
22 |
23 | Branch: {selectedBranch}
24 |
25 |
26 |
27 | Select Branch
28 |
29 |
30 |
31 |
32 | {branches && branches.map(branch => (
33 |
34 | ))}
35 |
36 |
37 |
38 |
39 |
40 |
41 | )
42 | }
43 |
44 |
45 |
46 | const mapStateToProps = (state) => {
47 | return{
48 | branches: state.firestore.ordered.branches,
49 | }
50 | }
51 |
52 |
53 | export default compose(connect(mapStateToProps), firestoreConnect([
54 | {
55 | collection: 'branches'
56 | },
57 | ]))(Students);
58 |
59 |
60 |
--------------------------------------------------------------------------------
/src/Dashboards/admin/pages/Teacher.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useParams } from 'react-router'
3 | import { Container } from 'reactstrap'
4 | import TeacherInfo from '../../../Components/Info/TeacherInfo';
5 |
6 |
7 | const Teacher = () => {
8 |
9 | const {teacher} = useParams();
10 |
11 |
12 | return(
13 |
14 | Teacher Details
15 |
16 |
17 | )
18 | }
19 |
20 |
21 | export default Teacher;
--------------------------------------------------------------------------------
/src/Dashboards/admin/pages/Teachers.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { firestoreConnect } from 'react-redux-firebase'
3 | import { Container, Input,Row, Col, Button} from 'reactstrap'
4 | import { compose } from 'redux'
5 | import {connect} from 'react-redux';
6 | import TeacherTable from '../../../Components/Table/TeacherTable'
7 |
8 |
9 |
10 | const Teachers = ({branches}) => {
11 | const [selectedBranch, setSelectedBranch] = useState('All');
12 |
13 | const handleBranch = (e) => {
14 | setSelectedBranch(e.target.value)
15 | }
16 |
17 |
18 | return(
19 |
20 | Teachers
21 |
22 |
23 | Branch: {selectedBranch}
24 |
25 |
26 |
27 | Select Branch
28 |
29 |
30 |
31 |
32 | {branches && branches.map(branch => (
33 |
34 | ))}
35 |
36 |
37 |
38 |
39 |
40 |
41 | )
42 | }
43 |
44 |
45 |
46 | const mapStateToProps = (state) => {
47 | return{
48 | branches: state.firestore.ordered.branches,
49 | }
50 | }
51 |
52 |
53 | export default compose(connect(mapStateToProps), firestoreConnect([
54 | {
55 | collection: 'branches'
56 | },
57 | ]))(Teachers);
58 |
59 |
--------------------------------------------------------------------------------
/src/Dashboards/forum/StudentForum.js:
--------------------------------------------------------------------------------
1 | import React, {useState} from 'react'
2 | import { connect } from 'react-redux'
3 | import { firestoreConnect } from 'react-redux-firebase'
4 | import { Container, Col, Row, Button, Card } from 'reactstrap'
5 | import CustomModal from '../../Components/Modal'
6 | import { compose } from 'redux'
7 | import ForumQuestionCard from '../../Components/Cards/ForumQuestionCard'
8 | import AddQuestionForm from '../../Components/Forms/AddQuestionForm'
9 |
10 |
11 | const StudentForum = ({user, questions}) => {
12 | let isStudent = user.userType === "Student" ? true : false;
13 | const [isOpen, setIsOpen] = useState(false)
14 |
15 | const toggle = () => setIsOpen(!isOpen);
16 |
17 | return(
18 |
19 | Student Forum
20 |
21 | {isStudent && }
22 |
23 |
24 | {questions && questions.map((question) => (
25 |
26 | ))}
27 |
28 |
29 |
30 |
31 |
32 | )
33 | }
34 |
35 |
36 | const mapStateToProps = (state) => {
37 | console.log(state)
38 | return{
39 | questions: state.firestore.ordered.studentquestions,
40 | user: state.firebase.profile
41 | }
42 | }
43 |
44 |
45 | export default compose(connect(mapStateToProps), firestoreConnect([
46 | {
47 | collection: 'studentquestions',
48 | }
49 | ]))(StudentForum);
--------------------------------------------------------------------------------
/src/Dashboards/student/StudentDashboard.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Redirect, Route, Switch } from 'react-router';
3 | import Footer from '../../Components/Footer/Footer';
4 | import { connect } from 'react-redux';
5 | import Home from './pages/Home'
6 | import ErrorPage from '../../Errorpage';
7 | import StudentForum from '../forum/StudentForum';
8 | import Courses from '../admin/pages/Courses'
9 | import Course from '../admin/pages/Course'
10 | import Assignments from '../admin/pages/Assignments'
11 |
12 | const StudentDashboard = ({profile, auth}) => {
13 | if(!auth.uid) return
14 | if(profile && profile.userType !== 'Student') return ()
15 |
16 | return(
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | )
28 | }
29 |
30 | const mapStateToProps = (state) => {
31 | return {
32 | auth: state.firebase.auth,
33 | profile: state.firebase.profile,
34 | }
35 | }
36 |
37 | export default connect(mapStateToProps)(StudentDashboard);
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/Dashboards/student/pages/Home.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { connect } from 'react-redux';
3 | import { firestoreConnect } from 'react-redux-firebase';
4 | import { Card, Row, Container, Col, CardTitle, CardText, Button } from 'reactstrap';
5 | import { compose } from 'redux';
6 | import Notification from '../../../Components/Notification';
7 | import Slider from '../../../Components/Slider';
8 |
9 |
10 |
11 | const TeacherOverview = ({profile, classes, notifications}) => {
12 | const myClasses = classes || []
13 | return(
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Welcome
23 | {profile.name}
24 |
25 |
26 | Your Classes
27 |
28 | {myClasses && myClasses.map((c) => (
29 |
30 |
31 | {c.course}
32 | {c.time}
33 |
38 |
39 |
40 | ))
41 | }
42 |
43 | {
44 | classes.length === 0 && No classes
45 | }
46 |
47 |
48 |
49 |
50 | )
51 | }
52 |
53 | const mapStateToProps = (state) => {
54 | console.log(state)
55 | return {
56 | profile: state.firebase.profile,
57 | classes: state.firestore.ordered.classes || [],
58 | notifications: state.firestore.ordered.notifications || [],
59 | }
60 | }
61 |
62 | export default compose(connect(mapStateToProps), firestoreConnect((props) => [
63 | {
64 | collection: 'classes',
65 | where: ["branch", "==", `${props.profile.Branch}`]
66 | },
67 | {
68 | collection: 'notifications',
69 | }
70 | ]))(TeacherOverview);
--------------------------------------------------------------------------------
/src/Dashboards/teacher/TeacherDashboard.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Redirect, Route, Switch } from 'react-router';
3 | import Footer from '../../Components/Footer/Footer';
4 | import { connect } from 'react-redux';
5 | import ErrorPage from '../../Errorpage';
6 | import TeacherOverview from './pages/TeacherOverview';
7 | import CustomAlert from '../../Components/Alert';
8 | import Courses from '../admin/pages/Courses';
9 | import Course from '../admin/pages/Course';
10 | import MyAssignments from './pages/MyAssignments';
11 | import MyClasses from './pages/MyClasses';
12 | import StudentForum from '../forum/StudentForum';
13 |
14 |
15 |
16 |
17 | const TeacherDashboard = ({profile, auth, authSuccess}) => {
18 | if(!auth.uid) return
19 | if(profile.userType !== 'Teacher') return ()
20 |
21 | return(
22 |
23 | {authSuccess && }
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | )
36 | }
37 |
38 | const mapStateToProps = (state) => {
39 | return {
40 | auth: state.firebase.auth,
41 | profile: state.firebase.profile,
42 | authSuccess: state.auth.authSuccess,
43 | }
44 | }
45 |
46 | export default connect(mapStateToProps)(TeacherDashboard);
47 |
48 |
--------------------------------------------------------------------------------
/src/Dashboards/teacher/pages/MyAssignments.js:
--------------------------------------------------------------------------------
1 | import React,{useState} from 'react'
2 | import { connect } from 'react-redux'
3 | import { firestoreConnect } from 'react-redux-firebase'
4 | import { compose } from 'redux'
5 | import { Container, Input,Row, Col, Button} from 'reactstrap'
6 | import CustomModal from '../../../Components/Modal/'
7 | import AssignmentContainer from '../../../Components/Containers/AssignmentContainer'
8 | import AddAssignmentForm from '../../../Components/Forms/AddAssignmentForm'
9 |
10 |
11 | const MyAssignments = ({profile}) => {
12 | const teacher = profile.name
13 |
14 | const [isOpen, setIsOpen] = useState(false)
15 |
16 | const toggle = () => setIsOpen(!isOpen);
17 |
18 |
19 | return(
20 |
21 | My Assignments
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | )
37 | }
38 |
39 |
40 | const mapStateToProps = (state) => {
41 | return{
42 | branches: state.firestore.ordered.branches,
43 | profile: state.firebase.profile
44 | }
45 | }
46 |
47 |
48 |
49 | export default compose(connect(mapStateToProps), firestoreConnect([
50 | {
51 | collection: 'branches'
52 | }
53 | ])) (MyAssignments);
--------------------------------------------------------------------------------
/src/Dashboards/teacher/pages/MyClasses.js:
--------------------------------------------------------------------------------
1 | import React,{useState} from 'react'
2 | import { connect } from 'react-redux'
3 | import { Container,Row, Col, Button} from 'reactstrap'
4 | import CustomModal from '../../../Components/Modal/'
5 | import ClassesContainer from '../../../Components/Containers/ClassesContainer'
6 | import AddClassForm from '../../../Components/Forms/AddClassForm'
7 |
8 |
9 | const MyClasses = ({profile}) => {
10 | const [isOpen, setIsOpen] = useState(false)
11 |
12 | const toggle = () => setIsOpen(!isOpen);
13 |
14 | const teacher = profile.name;
15 |
16 | return(
17 |
18 | My Classes
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | )
34 | }
35 |
36 | const mapStateToProps = (state) => {
37 | console.log(state)
38 | return{
39 | profile: state.firebase.profile
40 | }
41 | }
42 |
43 | export default connect(mapStateToProps)(MyClasses);
--------------------------------------------------------------------------------
/src/Dashboards/teacher/pages/TeacherOverview.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { connect } from 'react-redux';
3 | import { firestoreConnect } from 'react-redux-firebase';
4 | import { Card, Row, Container, Col, CardTitle, CardText, Button } from 'reactstrap';
5 | import { compose } from 'redux';
6 | import Notification from '../../../Components/Notification';
7 | import Slider from '../../../Components/Slider';
8 |
9 |
10 | const TeacherOverview = ({profile, classes, notifications}) => {
11 | return(
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | Welcome
21 | {profile.name}
22 |
23 |
24 | Your Classes
25 |
26 | {classes && classes.map((c) => (
27 |
28 |
29 | {c.course}
30 | {c.time}
31 |
36 |
37 |
38 | ))
39 | }
40 |
41 | {
42 | classes.length === 0 && No classes
43 | }
44 |
45 |
46 |
47 |
48 | )
49 | }
50 |
51 | const mapStateToProps = (state) => {
52 | console.log(state)
53 | return {
54 | profile: state.firebase.profile,
55 | classes: state.firestore.ordered.classes || [],
56 | notifications: state.firestore.ordered.notifications || []
57 | }
58 | }
59 |
60 | export default compose(connect(mapStateToProps), firestoreConnect((props) => [
61 | {
62 | collection: 'classes',
63 | where: ["teacher", "==", `${props.profile.name}`]
64 | },
65 | {
66 | collection: 'notifications',
67 | }
68 | ]))(TeacherOverview);
--------------------------------------------------------------------------------
/src/Errorpage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Container } from 'reactstrap';
3 |
4 |
5 | const ErrorPage = () => {
6 | return(
7 |
8 |
9 | 404
10 | Page not found!
11 |
12 |
13 | )
14 | }
15 |
16 |
17 | export default ErrorPage;
--------------------------------------------------------------------------------
/src/Hooks/useForm.js:
--------------------------------------------------------------------------------
1 | import {useState} from 'react';
2 |
3 | const useForm = (initialValues, callback) => {
4 | const [inputs, setInputs] = useState(initialValues);
5 | const handleSubmit = (event) => {
6 | if (event) event.preventDefault();
7 | callback();
8 | }
9 | const handleInputChange = (event) => {
10 | event.persist();
11 | setInputs(inputs => ({...inputs, [event.target.id]: event.target.value}));
12 | }
13 | return {
14 | handleSubmit,
15 | handleInputChange,
16 | inputs
17 | };
18 | }
19 | export default useForm;
20 |
--------------------------------------------------------------------------------
/src/Routes.js:
--------------------------------------------------------------------------------
1 | export const ADMIN_ROUTES = [
2 | {
3 | 'route' : 'Overview',
4 | 'url': '/'
5 | },
6 | {
7 | 'route': 'Courses',
8 | 'url': '/courses'
9 | },
10 | {
11 | 'route': 'Students',
12 | 'url': '/students'
13 | },
14 | {
15 | 'route': 'Assignments',
16 | 'url': '/assignments'
17 | },
18 | {
19 | 'route': 'Teachers',
20 | 'url': '/teachers'
21 | },
22 | {
23 | 'route': 'Admins',
24 | 'url': '/admins'
25 | }
26 | ]
27 |
28 |
29 | export const TEACHER_ROUTES = [
30 | {
31 | 'route' : 'Home',
32 | 'url': '/'
33 | },
34 | {
35 | 'route': 'My Classes',
36 | 'url': '/myclasses'
37 | },
38 | {
39 | 'route': 'Courses',
40 | 'url': '/courses'
41 | },
42 | {
43 | 'route': 'My Assignments',
44 | 'url': '/myassignments'
45 | },
46 | {
47 | 'route': 'Student Questions',
48 | 'url': '/forum'
49 | }
50 | ];
51 |
52 | export const STUDENT_ROUTES = [
53 | {
54 | 'route': 'Home',
55 | 'url':'/'
56 | },
57 | {
58 | 'route': 'Courses',
59 | 'url': '/courses'
60 | },
61 | {
62 | 'route': 'Assignments',
63 | 'url': '/assignments'
64 | },
65 | {
66 | 'route': 'Forum',
67 | 'url': '/forum'
68 | },
69 | ];
--------------------------------------------------------------------------------
/src/Store/actions/assignmentActions.js:
--------------------------------------------------------------------------------
1 | import { storage } from "../../config/fbConfig";
2 |
3 | export const addNewAssignment = (assignment) => {
4 | return (dispatch, getState, {getFirestore}) => {
5 | const firestore = getFirestore();
6 |
7 | console.log(assignment)
8 |
9 | firestore
10 | .add({collection: 'assignments'},
11 | {
12 | question: assignment.question,
13 | branch: assignment.branch,
14 | teacher: assignment.teacher,
15 | course: assignment.course,
16 | questionUrl: assignment.url,
17 | lastDate: assignment.lastDate,
18 | submissions: []
19 | }).catch((err)=> {
20 | console.log(err)
21 | })
22 | }
23 | }
24 |
25 |
26 | export const removeAssignment = (assignment) => {
27 | return (dispatch, getState, {getFirebase}) => {
28 | const firestore = getFirebase().firestore();
29 | firestore
30 | .collection('assignments')
31 | .doc(assignment.id)
32 | .delete()
33 | .then(() => {
34 | dispatch({
35 | type: 'REMOVED_ASSIGNMENT'
36 | })
37 | })
38 | .catch((err) => {
39 | dispatch({
40 | type: 'REMOVE_ASSIGNMENT_ERR',
41 | err
42 | })
43 | })
44 | }
45 | }
46 |
47 |
48 | export const addMarks = (assignment, submission, marks) => {
49 | return (dispatch, getState, {getFirebase}) => {
50 | const firebase = getFirebase();
51 | const firestore = getFirebase().firestore();
52 |
53 | console.log(assignment, submission, marks)
54 |
55 |
56 | firestore
57 | .collection('assignments')
58 | .doc(assignment.id)
59 | .set(
60 | { submissions: [{name: submission.name, url: submission.url, marks: marks, srn: submission.srn}] },
61 | { merge: true }
62 | )
63 | .then(() => {
64 | dispatch({
65 | type: 'REMOVED_ASSIGNMENT'
66 | })
67 | })
68 | .catch((err) => {
69 | dispatch({
70 | type: 'REMOVE_ASSIGNMENT_ERR',
71 | err
72 | })
73 | })
74 | }
75 | }
76 |
77 | export const addNewSubmission = (assignment, student, url, srn) => {
78 | return (dispatch, getState, {getFirebase}) => {
79 | const firebase = getFirebase();
80 | const firestore = getFirebase().firestore();
81 |
82 | firestore
83 | .collection('assignments')
84 | .doc(assignment.id)
85 | .update({
86 | submissions: firebase.firestore.FieldValue.arrayUnion({
87 | srn: srn,
88 | name: student,
89 | url: url
90 | })
91 | })
92 | .catch((err)=> {
93 | console.log(err)
94 | })
95 | }
96 | }
--------------------------------------------------------------------------------
/src/Store/actions/authActions.js:
--------------------------------------------------------------------------------
1 | import { uid } from 'uid';
2 |
3 | export const signIn = (credentials) => {
4 |
5 | return (dispatch, getState, {getFirebase}) => {
6 | const firebase = getFirebase();
7 |
8 | firebase.auth().signInWithEmailAndPassword(
9 | credentials.email,
10 | credentials.password
11 | ).then(() => {
12 | dispatch({ type: 'LOGIN_SUCCESS' });
13 | }).catch((err) => {
14 | dispatch({ type: 'LOGIN_ERROR', err });
15 | });
16 |
17 | }
18 | }
19 |
20 | export const signOut = () => {
21 | return (dispatch, getState, {getFirebase}) => {
22 | const firebase = getFirebase();
23 |
24 | firebase.auth().signOut().then(() => {
25 | dispatch({ type: 'SIGNOUT_SUCCESS' })
26 | });
27 | }
28 | }
29 |
30 | export const signUp = (newUser) => {
31 | return (dispatch, getState, {getFirebase, getFirestore}) => {
32 | const firebase = getFirebase();
33 | const firestore = getFirestore();
34 |
35 | firebase.auth().createUserWithEmailAndPassword(
36 | newUser.email,
37 | newUser.password
38 | ).then(resp => {
39 | return firestore.collection('users').doc(resp.user.uid).set({
40 | name: newUser.name,
41 | SRN: `acad${newUser.branch}${uid()}`,
42 | Branch: newUser.branch,
43 | userType: newUser.type,
44 | phone: newUser.phone,
45 | email: newUser.email,
46 | gender: newUser.gender,
47 | semester: newUser.semester
48 | });
49 | }).then(() => {
50 | dispatch({ type: 'SIGNUP_SUCCESS' });
51 | }).catch((err) => {
52 | dispatch({ type: 'SIGNUP_ERROR', err});
53 | });
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/Store/actions/classActions.js:
--------------------------------------------------------------------------------
1 | export const addClass = (newClass) => {
2 | return (dispatch, getState, {getFirestore, getFirebase}) => {
3 | const firestore = getFirestore();
4 |
5 | firestore
6 | .add({collection: 'classes'},
7 | {
8 | course: newClass.course,
9 | branch: newClass.branch,
10 | teacher: newClass.teacher,
11 | link: newClass.link,
12 | time: newClass.time
13 | })
14 | .then((dispatch)=>{
15 | dispatch({type:'CREATE_CLASS'});
16 | }).catch((err)=>{
17 | dispatch({type:'CREATE_CLASS_ERROR'});
18 | });
19 |
20 | }
21 | }
22 |
23 | export const removeClass = (selectedClass) => {
24 | return (dispatch, getState, {getFirebase}) => {
25 | const firestore = getFirebase().firestore();
26 | firestore
27 | .collection('classes')
28 | .doc(selectedClass.id)
29 | .delete()
30 | .then(() => {
31 | dispatch({
32 | type: 'CLASS_REMOVED'
33 | })
34 | })
35 | .catch((err) => {
36 | dispatch({
37 | type: 'CLASS_REMOVE_ERR',
38 | err
39 | })
40 | })
41 | }
42 | }
--------------------------------------------------------------------------------
/src/Store/actions/courseActions.js:
--------------------------------------------------------------------------------
1 | import { storage } from "../../config/fbConfig";
2 | import { uid } from 'uid';
3 |
4 | export const addCourse = (course) => {
5 | return (dispatch, getState, {getFirestore, getFirebase}) => {
6 | const firestore = getFirestore();
7 |
8 | const date = new Date();
9 |
10 | const year = date.getFullYear()
11 |
12 | firestore
13 | .add({collection: 'courses'},
14 | {
15 | courseId: `${year}${course.branch}${uid()}`,
16 | title: course.title,
17 | branch: course.branch,
18 | teacher: course.teacher,
19 | videos: [],
20 | references: []
21 | })
22 | .then((dispatch)=>{
23 | dispatch({type:'CREATE_COURSE'});
24 | }).catch((err)=>{
25 | dispatch({type:'CREATE_COURSE_ERROR'});
26 | });
27 |
28 | }
29 | }
30 |
31 | export const removeCourse = (course) => {
32 | return (dispatch, getState, {getFirebase}) => {
33 | const firestore = getFirebase().firestore();
34 | firestore
35 | .collection('courses')
36 | .doc(course.id)
37 | .delete()
38 | .then(() => {
39 | dispatch({
40 | type: 'REMOVED_COURSE'
41 | })
42 | })
43 | .catch((err) => {
44 | dispatch({
45 | type: 'REMOVE_TASK_ERR',
46 | err
47 | })
48 | })
49 | }
50 | }
51 |
52 |
53 | export const addNewVideo = (course, title, url) => {
54 | return (dispatch, getState, {getFirebase}) => {
55 | const firebase = getFirebase();
56 | const firestore = getFirebase().firestore();
57 |
58 | firestore
59 | .collection('courses')
60 | .doc(course[0].id)
61 | .update({
62 | videos: firebase.firestore.FieldValue.arrayUnion({
63 | name: title,
64 | url: url
65 | })
66 | })
67 | .catch((err)=> {
68 | console.log(err)
69 | dispatch({
70 | type: 'IMAGE_UPLOAD_ERROR',
71 | error: err,
72 | })
73 | })
74 | }
75 | }
76 |
77 |
78 |
79 | export const removeVideo = (course, title, url) => {
80 | return (dispatch, getState, {getFirebase}) => {
81 | const firebase = getFirebase();
82 | const firestore = getFirebase().firestore();
83 |
84 | firestore
85 | .collection('courses')
86 | .doc(course[0].id)
87 | .update({
88 | videos: firebase.firestore.FieldValue.arrayRemove({
89 | name: title,
90 | url: url
91 | })
92 | })
93 | .then(() => {
94 | var deleteTask = storage.ref().child(`courseVideos/${title}`)
95 | deleteTask.delete().then(() => {
96 | console.log('Deleted File')
97 | }).catch((err) => {
98 | console.log(err)
99 | })
100 | })
101 | .catch((err)=> {
102 | console.log(err)
103 | dispatch({
104 | type: 'IMAGE_UPLOAD_ERROR',
105 | error: err,
106 | })
107 | })
108 | }
109 | }
110 |
111 |
112 | export const addResource = (course, title, url) => {
113 | return (dispatch, getState, {getFirebase}) => {
114 | const firebase = getFirebase();
115 | const firestore = getFirebase().firestore();
116 |
117 |
118 | firestore
119 | .collection('courses')
120 | .doc(course[0].id)
121 | .update({
122 | references: firebase.firestore.FieldValue.arrayUnion({
123 | name: title,
124 | url: url
125 | })
126 | })
127 | .catch((err)=> {
128 | console.log(err)
129 | dispatch({
130 | type: 'IMAGE_UPLOAD_ERROR',
131 | error: err,
132 | })
133 | })
134 | }
135 | }
136 |
137 |
138 | export const removeResource = (course, title, url) => {
139 | return (dispatch, getState, {getFirebase}) => {
140 | const firebase = getFirebase();
141 | const firestore = getFirebase().firestore();
142 |
143 | firestore
144 | .collection('courses')
145 | .doc(course[0].id)
146 | .update({
147 | references: firebase.firestore.FieldValue.arrayRemove({
148 | name: title,
149 | url: url
150 | })
151 | })
152 | .then(() => {
153 | var deleteTask = storage.ref().child(`courseResources/${title}`)
154 | deleteTask.delete().then(() => {
155 | console.log('Deleted File')
156 | }).catch((err) => {
157 | console.log(err)
158 | })
159 | })
160 | .catch((err)=> {
161 | console.log(err)
162 | dispatch({
163 | type: 'IMAGE_UPLOAD_ERROR',
164 | error: err,
165 | })
166 | })
167 | }
168 | }
--------------------------------------------------------------------------------
/src/Store/actions/forumActions.js:
--------------------------------------------------------------------------------
1 | export const addQuestion = (newQuestion) => {
2 | return (dispatch, getState, {getFirestore, getFirebase}) => {
3 | const firestore = getFirestore();
4 |
5 | firestore
6 | .add({collection: 'studentquestions'},
7 | {
8 | question: newQuestion.question,
9 | user: newQuestion.user,
10 | topic: newQuestion.topic,
11 | answers: []
12 | })
13 | .then((dispatch)=>{
14 | dispatch({type:'CREATE_COURSE'});
15 | }).catch((err)=>{
16 | dispatch({type:'CREATE_COURSE_ERROR'});
17 | });
18 |
19 | }
20 | }
21 |
22 | export const removeQuestion = (question) => {
23 | return (dispatch, getState, {getFirebase}) => {
24 | const firestore = getFirebase().firestore();
25 | firestore
26 | .collection('studentquestions')
27 | .doc(question.id)
28 | .delete()
29 | .then(() => {
30 | console.log("Deleted Question")
31 | })
32 | .catch((err) => {
33 | console.log(err)
34 | })
35 | }
36 | }
37 |
38 |
39 | export const addComment = (question, comment, user) => {
40 | return (dispatch, getState, {getFirebase}) => {
41 | const firebase = getFirebase();
42 | const firestore = getFirebase().firestore();
43 |
44 | firestore
45 | .collection('studentquestions')
46 | .doc(question.id)
47 | .update({
48 | answers: firebase.firestore.FieldValue.arrayUnion({
49 | user: user,
50 | comment:comment
51 | })
52 | })
53 | .catch((err)=> {
54 | console.log(err)
55 | })
56 | }
57 | }
58 |
59 |
60 | export const removeComment = (question, comment, user) => {
61 | return (dispatch, getState, {getFirebase}) => {
62 | const firebase = getFirebase();
63 | const firestore = getFirebase().firestore();
64 |
65 | firestore
66 | .collection('studentquestions')
67 | .doc(question.id)
68 | .update({
69 | answers: firebase.firestore.FieldValue.arrayRemove({
70 | user: user,
71 | comment:comment
72 | })
73 | })
74 | .catch((err)=> {
75 | console.log(err)
76 | })
77 | }
78 | }
--------------------------------------------------------------------------------
/src/Store/actions/notificationActions.js:
--------------------------------------------------------------------------------
1 | export const addNewNotification = (notification) => {
2 | return (dispatch, getState, {getFirestore, getFirebase}) => {
3 | const firestore = getFirestore();
4 |
5 | const date = new Date();
6 |
7 | firestore
8 | .add({collection: 'adminnotifications'},
9 | {
10 | title: notification.title,
11 | desc: notification.desc
12 | })
13 | .then((dispatch)=>{
14 | console.log('succ')
15 | }).catch((err)=>{
16 | console.log(err)
17 | });
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Store/actions/studentActions.js:
--------------------------------------------------------------------------------
1 | export const setStudentSuspended = (student) => {
2 | return (dispatch, getState, {getFirebase}) => {
3 | const firestore = getFirebase().firestore();
4 |
5 | firestore
6 | .collection('users')
7 | .doc(student.id)
8 | .set({
9 | ...student,
10 | suspended: !student.suspended
11 | }
12 | )
13 | .then(() => {
14 | dispatch({
15 | type: 'SUSPEND_STUDENT_SUCESSS',
16 | suspend: 'Student Suspended Successfully',
17 | });
18 | })
19 | .catch((err)=> {
20 | dispatch({
21 | type: 'SUSPEND_ERROR',
22 | err,
23 | })
24 | })
25 | }
26 | }
27 |
28 |
29 | export const updateStudentDisplayPic = (student, url) => {
30 | return (dispatch, getState, {getFirebase}) => {
31 | const firestore = getFirebase().firestore();
32 |
33 | firestore
34 | .collection('users')
35 | .doc(student.id)
36 | .update({
37 | img: url
38 | })
39 | .then(() => {
40 | dispatch({
41 | type: 'IMAGE_UPLOADED',
42 | success: 'Image Uploaded SuccessFully',
43 | });
44 | })
45 | .catch((err)=> {
46 | dispatch({
47 | type: 'IMAGE_UPLOAD_ERROR',
48 | error: err,
49 | })
50 | })
51 | }
52 | }
53 |
54 |
55 | export const updateStudentInfo = (student) => {
56 | return(dispatch, getState, {getFirebase}) => {
57 | const firestore = getFirebase().firestore();
58 |
59 | console.log(student)
60 |
61 | firestore
62 | .collection('users')
63 | .doc(student.id)
64 | .set({
65 | father: student.father || '',
66 | mother: student.mother || '',
67 | dob: student.dob || '',
68 | email: student.email || '',
69 | sslc: student.sslc || '',
70 | puc: student.puc || '',
71 | rank: student.rank || '',
72 | Branch: student.branch || '',
73 | semester: student.semester || '',
74 | address: student.address || ''
75 | },
76 | {merge: true}
77 | )
78 | .then(() => {
79 | dispatch({
80 | type: 'STUDENT_UPDATED',
81 | success: 'Student Info Updated'
82 | })
83 | })
84 | .catch((err) => {
85 | dispatch({
86 | type: 'STUDENT_UPDATE_FAILED',
87 | error: err
88 | })
89 | })
90 | }
91 | }
--------------------------------------------------------------------------------
/src/Store/actions/teacherActions.js:
--------------------------------------------------------------------------------
1 | export const updateTeacherDisplayPic = (teacher, url) => {
2 | return (dispatch, getState, {getFirebase}) => {
3 | const firestore = getFirebase().firestore();
4 |
5 | firestore
6 | .collection('users')
7 | .doc(teacher.id)
8 | .update({
9 | img: url
10 | })
11 | .catch((err)=> {
12 | console.log(err)
13 | })
14 | }
15 | }
16 |
17 |
18 |
19 | export const updateTeacherInfo = (teacher) => {
20 | return(dispatch, getState, {getFirebase}) => {
21 | const firestore = getFirebase().firestore();
22 |
23 | firestore
24 | .collection('users')
25 | .doc(teacher.id)
26 | .set({
27 | father: teacher.father || '',
28 | mother: teacher.mother || '',
29 | dob: teacher.dob || '',
30 | email: teacher.email || '',
31 | sslc: teacher.sslc || '',
32 | puc: teacher.puc || '',
33 | rank: teacher.rank || '',
34 | Branch: teacher.branch || '',
35 | bachelor: teacher.bachelors || '',
36 | master: teacher.master || '',
37 | semester: teacher.semester || '',
38 | address: teacher.address || ''
39 | },
40 | {merge: true}
41 | )
42 | .catch((err) => {
43 | console.log(err)
44 | })
45 | }
46 | }
--------------------------------------------------------------------------------
/src/Store/reducers/authReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | authError: null,
3 | authSuccess: null
4 | }
5 |
6 | const authReducer = (state = initState, action) => {
7 | switch(action.type){
8 | case 'LOGIN_ERROR':
9 | return {
10 | ...state,
11 | authError: action.err.message === "The password is invalid or the user does not have a password." ? "Invalid Password" : 'Try Again Later'
12 | }
13 | case 'LOGIN_SUCCESS':
14 | return {
15 | ...state,
16 | authError: null,
17 | authSuccess: 'Login Success'
18 | }
19 |
20 | case 'SIGNOUT_SUCCESS':
21 | return state;
22 |
23 | case 'SIGNUP_SUCCESS':
24 | return {
25 | ...state,
26 | authError: null,
27 | authSuccess: 'Signup Success'
28 | }
29 |
30 | case 'SIGNUP_ERROR':
31 | return {
32 | ...state,
33 | authError: action.err.message
34 | }
35 |
36 | default:
37 | return state
38 | }
39 | };
40 |
41 | export default authReducer;
42 |
--------------------------------------------------------------------------------
/src/Store/reducers/coursesReducer.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shashankbhat2/lms/f40dd5f6c42ac1a87dbf1b73ae5a8cf64c85c09e/src/Store/reducers/coursesReducer.js
--------------------------------------------------------------------------------
/src/Store/reducers/rootReducer.js:
--------------------------------------------------------------------------------
1 | import {combineReducers} from 'redux';
2 | import {firestoreReducer} from 'redux-firestore';
3 | import {firebaseReducer} from 'react-redux-firebase'
4 | import authReducer from './authReducer';
5 | import studentReducer from './studentReducer';
6 |
7 |
8 | const rootReducer = combineReducers({
9 | auth: authReducer,
10 | student: studentReducer,
11 | firestore: firestoreReducer,
12 | firebase: firebaseReducer
13 | })
14 |
15 | export default rootReducer;
--------------------------------------------------------------------------------
/src/Store/reducers/studentReducer.js:
--------------------------------------------------------------------------------
1 | const initialState = {
2 | suspend: '',
3 | edited: '',
4 | upload: '',
5 | }
6 |
7 |
8 | const studentReducer = (state= initialState, action) => {
9 | switch(action.type){
10 | case 'SUSPEND_STUDENT_SUCESSS': {
11 | return {
12 | ...state,
13 | suspend: action.suspend,
14 | }
15 | };
16 | case 'SUSPEND_ERROR': {
17 | return{
18 | ...state,
19 | suspend: action.error
20 | }
21 | };
22 | case 'STUDENT_UPDATE_FAILED': {
23 | return{
24 | ...state,
25 | edited: action.error
26 | }
27 | };
28 | case 'STUDENT_UPDATED': {
29 | return{
30 | ...state,
31 | edited: action.success
32 | }
33 | };
34 | case 'IMAGE_UPLOADED': {
35 | return{
36 | ...state,
37 | upload: action.success
38 | }
39 | };
40 | case 'IMAGE_UPLOAD_ERROR': {
41 | return{
42 | ...state,
43 | upload: action.error
44 | }
45 | };
46 | default:
47 | return state;
48 | }
49 | }
50 |
51 | export default studentReducer;
52 |
53 |
54 |
--------------------------------------------------------------------------------
/src/config/fbConfig.js:
--------------------------------------------------------------------------------
1 | import firebase from 'firebase/app';
2 | import 'firebase/firestore';
3 | import 'firebase/functions'
4 | import 'firebase/auth';
5 | import 'firebase/analytics';
6 | import 'firebase/storage';
7 |
8 |
9 | const firebaseConfig = {
10 | apiKey: process.env.REACT_APP_APIKEY,
11 | authDomain: process.env.REACT_APP_AUTHDOMAIN,
12 | databaseURL: process.env.REACT_APP_DB,
13 | projectId: process.env.REACT_APP_PID,
14 | storageBucket: process.env.REACT_APP_SB,
15 | messagingSenderId: process.env.REACT_APP_SID,
16 | appId: process.env.REACT_APP_APPID,
17 | measurementId:process.env.REACT_APP_MID
18 | }
19 | // Initialize Firebase
20 | firebase.initializeApp(firebaseConfig);
21 | firebase.firestore();
22 |
23 | const storage = firebase.storage();
24 | const functions = firebase.functions();
25 |
26 | export {
27 | storage,
28 | functions,
29 | firebase as default
30 | }
31 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 | import 'bootstrap/dist/css/bootstrap.min.css';
5 | import 'video-react/dist/video-react.css';
6 | import { BrowserRouter } from 'react-router-dom';
7 | import { reduxFirestore, getFirestore,createFirestoreInstance} from 'redux-firestore';
8 | import {ReactReduxFirebaseProvider,getFirebase} from 'react-redux-firebase';
9 | import thunk from 'redux-thunk'
10 | import { applyMiddleware, compose, createStore } from 'redux';
11 | import rootReducer from './Store/reducers/rootReducer';
12 | import fbConfig from './config/fbConfig'
13 | import { Provider } from 'react-redux';
14 | import firebase from 'firebase/app';
15 | import { useSelector } from 'react-redux';
16 | import { isLoaded } from 'react-redux-firebase';
17 |
18 |
19 | const store = createStore(
20 | rootReducer,
21 | compose(
22 | applyMiddleware(thunk.withExtraArgument({ getFirestore, getFirebase })),
23 | reduxFirestore(fbConfig)
24 | )
25 | );
26 |
27 | const profileSpecificProps = {
28 | userProfile: 'users',
29 | useFirestoreForProfile: true,
30 | enableRedirectHandling: false,
31 | resetBeforeLogin: false
32 | }
33 |
34 | const newfbConfig = Object.assign(fbConfig,profileSpecificProps);
35 |
36 |
37 |
38 | const rrfProps = {
39 | firebase,
40 | config: newfbConfig,
41 | dispatch: store.dispatch,
42 | createFirestoreInstance
43 | };
44 |
45 |
46 | function AuthIsLoaded({ children }) {
47 | const auth = useSelector(state => state.firebase.auth)
48 | if (!isLoaded(auth)) return (
49 |
50 |
51 | );
52 | return children
53 | }
54 |
55 |
56 |
57 | ReactDOM.render(
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | ,
67 | document.getElementById('root')
68 | );
69 |
70 |
--------------------------------------------------------------------------------