├── .babelrc ├── .env.sample ├── .eslintrc ├── .gitignore ├── LICENSE ├── README.md ├── bower.json ├── client ├── assets │ ├── data │ │ ├── Courses.js │ │ ├── Lecturers.js │ │ └── Lectures.js │ ├── img │ │ ├── course-image.jpg │ │ ├── logo.png │ │ ├── profile-pic-2.jpeg │ │ ├── profile-pic-3.jpeg │ │ ├── profile-pic-4.jpeg │ │ └── profile-pic.jpg │ └── styles │ │ └── styles.css ├── components │ ├── App.jsx │ ├── Dashboard │ │ ├── AllCourses.jsx │ │ ├── CourseBanner.jsx │ │ ├── CourseCard.jsx │ │ ├── CourseDetails.jsx │ │ ├── DashboardPage.jsx │ │ ├── LectureDetails.jsx │ │ ├── LecturersDetails.jsx │ │ ├── SingleCourse.jsx │ │ └── SingleCoursePage.jsx │ ├── Footer │ │ └── Footer.jsx │ ├── Main │ │ ├── Home.jsx │ │ └── SigninForm.jsx │ └── NavigationBar │ │ ├── NavigationBar.jsx │ │ └── Sidebar.jsx ├── index.html ├── index.js ├── index.test.js └── routes.js ├── package-lock.json ├── package.json ├── tools ├── server.js └── startMessage.js └── webpack.config.dev.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"] 3 | } -------------------------------------------------------------------------------- /.env.sample: -------------------------------------------------------------------------------- 1 | PORT=8400 -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint:recommended", 4 | "plugin:import/errors", 5 | "plugin:import/warnings" 6 | ], 7 | "plugins": [ 8 | "react" 9 | ], 10 | "parserOptions": { 11 | "ecmaVersion": 6, 12 | "sourceType": "module", 13 | "ecmaFeatures": { 14 | "jsx": true 15 | } 16 | }, 17 | "env": { 18 | "es6": true, 19 | "browser": true, 20 | "node": true, 21 | "jquery": true, 22 | "mocha": true 23 | }, 24 | "rules": { 25 | "quotes": 0, 26 | "no-console": 2, 27 | "no-debugger": 1, 28 | "no-var": 1, 29 | "semi": [1, "always"], 30 | "no-trailing-spaces": 1, 31 | "eol-last": 2, 32 | "no-unused-vars": 0, 33 | "no-underscore-dangle": 0, 34 | "no-alert": 2, 35 | "no-lone-blocks": 0, 36 | "jsx-quotes": 1, 37 | "react/display-name": [ 1, {"ignoreTranspilerName": false }], 38 | "react/forbid-prop-types": [1, {"forbid": ["any"]}], 39 | "react/jsx-boolean-value": 1, 40 | "react/jsx-closing-bracket-location": 0, 41 | "react/jsx-curly-spacing": 1, 42 | "react/jsx-indent-props": 0, 43 | "react/jsx-key": 1, 44 | "react/jsx-max-props-per-line": 0, 45 | "react/jsx-no-bind": 1, 46 | "react/jsx-no-duplicate-props": 1, 47 | "react/jsx-no-literals": 0, 48 | "react/jsx-no-undef": 1, 49 | "react/jsx-pascal-case": 1, 50 | "react/jsx-sort-prop-types": 0, 51 | "react/jsx-sort-props": 0, 52 | "react/jsx-uses-react": 1, 53 | "react/jsx-uses-vars": 1, 54 | "react/no-danger": 1, 55 | "react/no-did-mount-set-state": 1, 56 | "react/no-did-update-set-state": 1, 57 | "react/no-direct-mutation-state": 1, 58 | "react/no-multi-comp": 1, 59 | "react/no-set-state": 0, 60 | "react/no-unknown-property": 1, 61 | "react/prefer-es6-class": 1, 62 | "react/prop-types": 1, 63 | "react/react-in-jsx-scope": 1, 64 | "react/self-closing-comp": 1, 65 | "react/sort-comp": 1, 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | .DS_Store 61 | 62 | bower_components 63 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Orjiewuru Kingdom Isaac 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Moodle 2 | 3 | Learning Resource for Students Built for my ForLoopCU talk - Oct 7, 2017 4 | 5 | ### A minimal redesign on Covenant University's current application - Moodle 6 | 7 | screen shot 2017-10-07 at 9 40 54 am 8 | screen shot 2017-10-07 at 9 38 18 pm 9 | screen shot 2017-10-07 at 9 43 46 am 10 | screen shot 2017-10-07 at 9 41 05 am 11 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "moodle", 3 | "description": "Learning Resource for Students", 4 | "main": "index.js", 5 | "authors": [ 6 | "kingisaac95" 7 | ], 8 | "license": "MIT", 9 | "keywords": [ 10 | "learning" 11 | ], 12 | "homepage": "", 13 | "private": true, 14 | "ignore": [ 15 | "**/.*", 16 | "node_modules", 17 | "bower_components", 18 | "test", 19 | "tests" 20 | ], 21 | "dependencies": { 22 | "jquery": "^3.2.1", 23 | "bootstrap": "3.3.7" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /client/assets/data/Courses.js: -------------------------------------------------------------------------------- 1 | export const Courses = [ 2 | { 3 | courseImage: require(`../../assets/img/course-image.jpg`), 4 | title: 'GEC 117', 5 | description: 'Intro to Technical Drawing', 6 | lecturer1: require(`../../assets/img/profile-pic.jpg`), 7 | lecturer2: require(`../../assets/img/profile-pic-4.jpeg`), 8 | lecturer3: require(`../../assets/img/profile-pic-3.jpeg`), 9 | }, 10 | { 11 | courseImage: require(`../../assets/img/course-image.jpg`), 12 | title: 'GEC 212', 13 | description: 'Intermediate to Technical Drawing', 14 | lecturer1: require(`../../assets/img/profile-pic.jpg`), 15 | lecturer2: require(`../../assets/img/profile-pic-4.jpeg`), 16 | lecturer3: require(`../../assets/img/profile-pic-3.jpeg`), 17 | }, 18 | { 19 | courseImage: require(`../../assets/img/course-image.jpg`), 20 | title: 'GEC Nothing', 21 | description: 'Advanced waste fo time', 22 | lecturer1: require(`../../assets/img/profile-pic.jpg`), 23 | lecturer2: require(`../../assets/img/profile-pic-4.jpeg`), 24 | lecturer3: require(`../../assets/img/profile-pic-3.jpeg`), 25 | }, 26 | ]; 27 | 28 | -------------------------------------------------------------------------------- /client/assets/data/Lecturers.js: -------------------------------------------------------------------------------- 1 | export const Lecturers = [ 2 | { 3 | profileImage: require('../../assets/img/profile-pic.jpg'), 4 | name: 'Orjiewuru K, Ph.D', 5 | position: 'Professor', 6 | }, 7 | { 8 | profileImage: require('../../assets/img/profile-pic-2.jpeg'), 9 | name: 'Garry Joe', 10 | position: 'Lead Lecturer', 11 | }, 12 | { 13 | profileImage: require('../../assets/img/profile-pic-3.jpeg'), 14 | name: 'Kerry Paul', 15 | position: 'Lecturer 2', 16 | }, 17 | { 18 | profileImage: require('../../assets/img/profile-pic-4.jpeg'), 19 | name: 'Janet Doe', 20 | position: 'Assistant Lecturer', 21 | }, 22 | ]; 23 | 24 | -------------------------------------------------------------------------------- /client/assets/data/Lectures.js: -------------------------------------------------------------------------------- 1 | export const Lectures = [ 2 | { 3 | title: 'Lecture 1 - Why you should care about TD.ppt', 4 | description: 'Description is not available', 5 | date_updated: 'UPLOADED 01.OCT.2017', 6 | }, 7 | { 8 | title: 'Lecture 2 - Why you shouldn\'t care about TD.ppt', 9 | description: 'Description is not available', 10 | date_updated: 'UPLOADED 01.OCT.2017', 11 | }, 12 | { 13 | title: 'Lecture 3 - Another boring lecture on TD.ppt', 14 | description: 'Description is not available', 15 | date_updated: 'UPLOADED 01.OCT.2017', 16 | }, 17 | ]; 18 | 19 | -------------------------------------------------------------------------------- /client/assets/img/course-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kingisaac95/moodle/0a9da27896e807b3f950d5ac4e2ef2267355b87d/client/assets/img/course-image.jpg -------------------------------------------------------------------------------- /client/assets/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kingisaac95/moodle/0a9da27896e807b3f950d5ac4e2ef2267355b87d/client/assets/img/logo.png -------------------------------------------------------------------------------- /client/assets/img/profile-pic-2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kingisaac95/moodle/0a9da27896e807b3f950d5ac4e2ef2267355b87d/client/assets/img/profile-pic-2.jpeg -------------------------------------------------------------------------------- /client/assets/img/profile-pic-3.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kingisaac95/moodle/0a9da27896e807b3f950d5ac4e2ef2267355b87d/client/assets/img/profile-pic-3.jpeg -------------------------------------------------------------------------------- /client/assets/img/profile-pic-4.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kingisaac95/moodle/0a9da27896e807b3f950d5ac4e2ef2267355b87d/client/assets/img/profile-pic-4.jpeg -------------------------------------------------------------------------------- /client/assets/img/profile-pic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kingisaac95/moodle/0a9da27896e807b3f950d5ac4e2ef2267355b87d/client/assets/img/profile-pic.jpg -------------------------------------------------------------------------------- /client/assets/styles/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100%; 3 | box-sizing: border-box; 4 | } 5 | 6 | body { 7 | font-family: 'Open Sans', sans-serif; 8 | margin: 0; 9 | min-height: 100%; 10 | } 11 | 12 | nav.navbar { 13 | background-color: #ffffff; 14 | } 15 | 16 | .navbar-brand { 17 | padding: 10px 15px; 18 | } 19 | 20 | .user-name-and-icon { 21 | margin: 10px 25px; 22 | } 23 | 24 | .user-name-and-icon > a { 25 | text-decoration: none; 26 | color: #000000; 27 | margin: 10px; 28 | } 29 | 30 | #home { 31 | margin-top: 10%; 32 | } 33 | 34 | div.login { 35 | padding: 20px 50px 20px 50px; 36 | box-shadow: 0 2px 3px 0 rgba(0,0,0,0.2); 37 | } 38 | 39 | .form-control.login { 40 | padding: 20px; 41 | background-color: #F2F2F2; 42 | } 43 | 44 | .form-control.search, button.search, button.search:hover { 45 | border-style: none; 46 | background-color: #F2F2F2; 47 | } 48 | 49 | .form-control.login:focus { 50 | outline: none; 51 | } 52 | 53 | .btn.login { 54 | margin-top: 20px; 55 | padding: 10px 40px; 56 | } 57 | 58 | .btn.download { 59 | margin-top: 20px; 60 | padding: 15px 20px; 61 | } 62 | 63 | .btn.login, .btn.login:focus, .btn.download, .btn.download:focus { 64 | color: #ffffff; 65 | background-color: #7438CD; 66 | } 67 | 68 | input[type=email], input[type=text], input[type=password] { 69 | border-style: none; 70 | } 71 | 72 | input[type=email]:focus, input[type=text]:focus, input[type=password]:focus { 73 | box-shadow: none; 74 | } 75 | 76 | .dashboard { 77 | background-color: #f8f8f8; 78 | padding-bottom: 60px; 79 | } 80 | 81 | .side-bar, .course-details, .single-course { 82 | background-color: #ffffff; 83 | box-shadow: 0 2px 3px 0 rgba(0,0,0,0.2); 84 | } 85 | 86 | .side-bar, .course-details, .course-banner, .single-course { 87 | border-radius: 5px; 88 | } 89 | 90 | .side-bar { 91 | padding: 40px 20px; 92 | } 93 | 94 | .thumb-body > h4 { 95 | margin-bottom: 20px; 96 | } 97 | 98 | .nav-pills>li.active>a, .nav-pills>li.active>a:focus, .nav-pills>li.active>a:hover { 99 | background-color: #7438CD; 100 | border-radius: 0; 101 | } 102 | 103 | .nav-item { 104 | margin: 5px 10px; 105 | } 106 | 107 | a>i.not-active, .glyphicon-search { 108 | color: #7438CD; 109 | } 110 | 111 | span.not-active { 112 | color: #000000; 113 | } 114 | 115 | .single-course { 116 | padding: 0 0 30px 0; 117 | margin: 5px; 118 | } 119 | 120 | .col-md-4.single-course { 121 | width: 30%; 122 | } 123 | 124 | .thumb-header { 125 | min-height: 150px; 126 | } 127 | 128 | .thumb-header .overlay { 129 | position: absolute; 130 | top: 0; 131 | left: 0; 132 | width: 100%; 133 | height: 150px; 134 | background: rgba(0, 0, 0, .5); 135 | } 136 | 137 | .thumb-header > img { 138 | height: 150px; 139 | width: 100%; 140 | } 141 | 142 | .thumb-body { 143 | padding-left: 15px; 144 | padding-right: 15px; 145 | } 146 | 147 | p.taught-by { 148 | font-size: 18px; 149 | } 150 | 151 | .plus { 152 | margin: 20px; 153 | } 154 | 155 | .course-details { 156 | margin-top: 10px; 157 | } 158 | 159 | .course-details > ul { 160 | box-shadow: 0 2px 3px 0 rgba(0,0,0,0.2); 161 | } 162 | 163 | .course-banner { 164 | padding: 60px; 165 | background-color: #000000; 166 | color: #ffffff; 167 | } 168 | 169 | .nav-tabs { 170 | border: none; 171 | } 172 | 173 | .nav-tabs > li > a { 174 | margin-right: 2px; 175 | border: none; 176 | border-radius: 0; 177 | color: #4A4A4A; 178 | } 179 | 180 | .nav-tabs > li > a:hover { 181 | background-color: #7438CD; 182 | color: #ffffff; 183 | } 184 | 185 | .nav-tabs > li.active { 186 | color: #000; 187 | cursor: default; 188 | background-color: #fff; 189 | border: 0; 190 | border-bottom: 3px solid #7438CD; 191 | } 192 | 193 | .nav-tabs > li.active > a, .nav-tabs > li.active > a:focus { 194 | border: 0; 195 | } 196 | 197 | .tab-content { 198 | padding: 10px 60px 60px 60px; 199 | } 200 | 201 | .overview-title, #overview { 202 | padding: 20px; 203 | } 204 | 205 | .upload-date { 206 | color: #C0C3CB; 207 | } 208 | 209 | .description { 210 | color: #6F7176; 211 | } 212 | 213 | .notes-wrapper { 214 | border: 1px solid #CACED8; 215 | border-radius: 5px; 216 | padding: 5px 20px 20px 20px; 217 | margin-top: 20px; 218 | } 219 | 220 | p.lecture-details { 221 | font-size: 14px; 222 | } 223 | 224 | .lecture-details { 225 | padding: 2px; 226 | } 227 | 228 | .footer { 229 | position: absolute; 230 | right: 0; 231 | bottom: 0; 232 | left: 0; 233 | padding: 1rem; 234 | color: #ffffff; 235 | } 236 | 237 | .btn-pagination{ 238 | background-color: #7438CD; 239 | color: #ffffff; 240 | } 241 | 242 | -------------------------------------------------------------------------------- /client/components/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from "react"; 2 | import { NavigationBar } from "./NavigationBar/NavigationBar.jsx"; 3 | import { Home } from "../components/Main/Home.jsx"; 4 | import Footer from "./Footer/Footer.jsx"; 5 | 6 | export default class App extends Component { 7 | render() { 8 | return( 9 |
10 | { this.props.children } 11 |
12 | ); 13 | } 14 | } 15 | 16 | App.propTypes = { 17 | children: PropTypes.object.isRequired, 18 | }; 19 | -------------------------------------------------------------------------------- /client/components/Dashboard/AllCourses.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router'; 3 | import { CourseCard } from './CourseCard.jsx'; 4 | import { Courses } from '../../assets/data/Courses'; 5 | 6 | export const AllCourses = () => { 7 | return ( 8 |
9 |
10 | 11 | 12 | 13 |
14 |
15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /client/components/Dashboard/CourseBanner.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const CourseBanner = () => { 4 | return ( 5 |
6 |

GEC 117

7 |

Introduction to Technical & Engineering Drawing

8 |
9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /client/components/Dashboard/CourseCard.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | 3 | export const CourseCard = ({courses}) => { 4 | return ( 5 |
6 | { 7 | courses.map((course, index) => 8 |
9 |
10 | image 11 |
12 |
13 |
14 |

{course.title}

15 |

{course.description}

16 |
17 |

Taught by

18 |
19 | image 20 | image 21 | image 22 | + 1 more 23 |
24 |
25 |
26 | ) 27 | } 28 |
29 | ); 30 | }; 31 | 32 | CourseCard.propTypes = { 33 | courses: PropTypes.array.isRequired 34 | }; 35 | -------------------------------------------------------------------------------- /client/components/Dashboard/CourseDetails.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { LecturersDetails } from './LecturersDetails.jsx'; 3 | import { LectureDetails } from './LectureDetails.jsx'; 4 | import { Lecturers } from '../../assets/data/Lecturers'; 5 | import { Lectures } from '../../assets/data/Lectures'; 6 | 7 | const questions = [ 8 | 'Do you know React?', 9 | 'What is computer science?', 10 | 'What is the full meaning of JSX?', 11 | 'Are you NORMAL?', 12 | ]; 13 | 14 | export class CourseDetails extends Component { 15 | constructor () { 16 | super(); 17 | 18 | this.state = { 19 | curQuestion: 1, 20 | disabled: false 21 | }; 22 | 23 | this.nextQuestion = this.nextQuestion.bind(this); 24 | } 25 | 26 | nextQuestion() { 27 | if (this.state.curQuestion === questions.length - 1) { 28 | this.setState((prev) => { 29 | return { 30 | curQuestion: prev.curQuestion + 1, 31 | disabled: true 32 | }; 33 | }); 34 | } else if (this.state.curQuestion < questions.length) { 35 | this.setState((prev) => { 36 | return { 37 | curQuestion: prev.curQuestion + 1 38 | }; 39 | }); 40 | } 41 | } 42 | 43 | render() { 44 | return ( 45 |
46 | 51 | 52 |
53 |
54 |

55 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 56 | Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure 57 | dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non 58 | proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 59 |

60 | 61 |

Course Lecturers

62 |
63 | 64 |
65 |
66 |
67 | 68 |
69 |
70 |
71 |
72 |

Sidebar here

73 |
74 |
75 |
82 |

{questions[this.state.curQuestion - 1]}

83 |
84 |
85 |

Prove yourself here

86 |