├── .gitignore ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── src ├── client │ ├── actions │ │ ├── index.js │ │ └── types.js │ ├── assets │ │ └── logo.svg │ ├── components │ │ ├── App.js │ │ ├── Category │ │ │ └── Category.js │ │ ├── Contributor │ │ │ └── ContributorForm.js │ │ ├── Landing │ │ │ ├── Landing.js │ │ │ ├── Login.js │ │ │ ├── gitHubLoginButton.js │ │ │ ├── landingPageCategoryButtons.js │ │ │ └── navbar.js │ │ └── Questionnaire │ │ │ ├── AnswerPage.js │ │ │ ├── QuestionPage.js │ │ │ ├── answerBox.js │ │ │ ├── backButton.js │ │ │ ├── categoryName.js │ │ │ ├── getAnswerButton.js │ │ │ ├── nextQuestionButton.js │ │ │ └── questionBox.js │ ├── containers │ │ ├── gitHubLoginContainer.js │ │ └── landingContainer.js │ ├── css │ │ ├── Contributor_Form.css │ │ ├── Landing.css │ │ ├── Question_Page.css │ │ └── general.css │ ├── index.js │ └── reducers │ │ ├── category_reducer.js │ │ ├── index.js │ │ └── question_answer.js ├── config │ └── keys.js └── server │ ├── model.js │ ├── routers.js │ └── server.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | bundle.js -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TheCodingGym -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | The Coding Gym 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "thecodinggym", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/simonpark107/TheCodingGym.git" 9 | }, 10 | "scripts": { 11 | "start": "./node_modules/.bin/webpack -w & nodemon src/server/server.js", 12 | "client": "./node_modules/.bin/webpack", 13 | "server": "nodemon src/server/server.js", 14 | "webpack": "./node_modules/.bin/webpack -w" 15 | }, 16 | "author": "", 17 | "license": "ISC", 18 | "bugs": { 19 | "url": "https://github.com/simonpark107/TheCodingGym/issues" 20 | }, 21 | "homepage": "https://github.com/simonpark107/TheCodingGym#readme", 22 | "dependencies": { 23 | "axios": "^0.18.0", 24 | "cookie-parser": "^1.4.3", 25 | "eslint": "^4.19.1", 26 | "express": "^4.16.3", 27 | "lodash": "^4.17.5", 28 | "material-ui": "^0.20.0", 29 | "mongoose": "^5.0.11", 30 | "path": "^0.12.7", 31 | "react": "^16.2.0", 32 | "react-dom": "^16.2.0", 33 | "react-github-login": "^1.0.3", 34 | "react-redux": "^5.0.7", 35 | "react-router": "^4.2.0", 36 | "react-router-dom": "^4.2.2", 37 | "redux": "^3.7.2", 38 | "redux-form": "^7.3.0", 39 | "redux-promise": "^0.5.3", 40 | "redux-thunk": "^2.2.0", 41 | "request": "^2.85.0", 42 | "reset-css": "^3.0.0" 43 | }, 44 | "devDependencies": { 45 | "babel": "^6.23.0", 46 | "babel-core": "^6.26.0", 47 | "babel-loader": "^7.1.4", 48 | "babel-polyfill": "^6.26.0", 49 | "babel-preset-es2015": "^6.24.1", 50 | "babel-preset-react": "^6.24.1", 51 | "babel-preset-stage-0": "^6.24.1", 52 | "babel-preset-stage-1": "^6.24.1", 53 | "babel-preset-stage-2": "^6.24.1", 54 | "babel-preset-stage-3": "^6.24.1", 55 | "css-loader": "^0.28.11", 56 | "eslint-config-airbnb": "^16.1.0", 57 | "eslint-plugin-import": "^2.9.0", 58 | "eslint-plugin-jsx-a11y": "^6.0.3", 59 | "eslint-plugin-react": "^7.7.0", 60 | "file-loader": "^1.1.11", 61 | "image-webpack-loader": "^4.2.0", 62 | "nodemon": "^1.17.2", 63 | "react-svg-loader": "^2.1.0", 64 | "react-test-renderer": "^16.2.0", 65 | "style-loader": "^0.20.3", 66 | "svg-react-loader": "^0.4.5", 67 | "url-loader": "^1.0.1", 68 | "webpack": "^3.10.0", 69 | "webpack-cli": "^2.0.13" 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/client/actions/index.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { 3 | CREATE_CONTRIBUTION, 4 | FETCH_QUESTIONS, 5 | FETCH_QUESTION, 6 | FETCH_ANSWER, 7 | DELETE_QUESTION 8 | } from './types'; 9 | 10 | // CREATE CATEGORY, QUESTION & ANSWER 11 | export function createContribution(values, callback) { 12 | console.log('ACTION VALUES === ', values); 13 | 14 | //make api request. After api is resolved then call the callback function 15 | const request = axios.post('api/questions', values).then(() => callback()); 16 | 17 | return { 18 | type: CREATE_CONTRIBUTION, 19 | payload: request 20 | }; 21 | } 22 | 23 | // FETCH ALL QUESTIONS OF SPECIFIED CATEGORY 24 | export const fetchQuestions = (category, topic) => async dispatch => { 25 | console.log('this is fetchQ category', category); 26 | console.log('this is fetchQ topic', topic); 27 | 28 | const request = await axios({ 29 | method: 'post', 30 | url: 'api/questions/', 31 | data: { category, topic } 32 | }); 33 | 34 | console.log('=== ACTION ===', request); 35 | 36 | dispatch({ 37 | type: FETCH_QUESTIONS, 38 | payload: request 39 | }); 40 | }; 41 | 42 | // FETCH SPECIFIC QUESTION 43 | export const fetchQuestion = e => async dispatch => { 44 | 45 | dispatch({ 46 | type: FETCH_QUESTION, 47 | payload: e 48 | }); 49 | }; 50 | -------------------------------------------------------------------------------- /src/client/actions/types.js: -------------------------------------------------------------------------------- 1 | //CREATE DATA 2 | export const CREATE_CONTRIBUTION = 'create_contribution'; 3 | 4 | //GET ALL QUESTIONS 5 | export const FETCH_QUESTIONS = 'fetch_questions'; 6 | 7 | //GET SPECIFIC QUESTION 8 | export const FETCH_QUESTION = 'fetch_question'; 9 | 10 | //GET SPECIFIC ANSWER 11 | export const FETCH_ANSWER = 'fetch_answer'; 12 | 13 | //DELETE SPECIFIC DATA 14 | export const DELETE_QUESTION = 'delete_question'; 15 | -------------------------------------------------------------------------------- /src/client/assets/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/client/components/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import { Route, Redirect, Switch } from "react-router-dom"; 3 | import Navbar from "./Landing/navbar" 4 | import Landing from "./Landing/Landing"; 5 | import Category from "./Category/Category"; 6 | import QuestionPage from "./Questionnaire/QuestionPage"; 7 | import ContributorForm from "./Contributor/ContributorForm"; 8 | import AnswerPage from "./Questionnaire/AnswerPage" 9 | import reset from "reset-css"; 10 | 11 | class App extends Component { 12 | constructor(props) { 13 | super(props); 14 | this.state = { 15 | contributor: false 16 | }; 17 | } 18 | 19 | render() { 20 | return ( 21 |
22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
32 |
33 | ); 34 | } 35 | } 36 | 37 | export default App; 38 | -------------------------------------------------------------------------------- /src/client/components/Category/Category.js: -------------------------------------------------------------------------------- 1 | // REACT 2 | import React, { Component } from 'react'; 3 | import { Link } from 'react-router-dom'; 4 | import { withRouter } from 'react-router'; 5 | 6 | // REDUX 7 | import { connect } from 'react-redux'; 8 | 9 | // MATERIAL UI 10 | import RaisedButton from 'material-ui/RaisedButton'; 11 | 12 | //LODASH 13 | import _ from 'lodash'; 14 | 15 | // ACTION CREATOR 16 | import { fetchQuestion } from './../../actions'; 17 | 18 | class Category extends Component { 19 | handleClick = e => { 20 | this.props.fetchQuestion(e); 21 | // this.props.fetchQuestion(e).then(() => this.props.history.push('/questionpage')); 22 | }; 23 | 24 | renderCategoryName = () => { 25 | const data = this.props.category; 26 | console.log('this is data!', data); 27 | let selectedCategory = data[0].results[0].category; 28 | return selectedCategory; 29 | }; 30 | 31 | renderQuestions = () => { 32 | const categoryList = this.props.category; 33 | console.log('=== CATEGORY ===', categoryList); 34 | let arr = categoryList[0].results; //returns questions and id 35 | 36 | console.log('this is array in renderQ', arr); 37 | return ( 38 |
39 | {arr.map(el => { 40 | return ( 41 | this.handleClick(el)} to="/questionpage" key={el._id}> 42 | 48 | 49 | ); 50 | })} 51 |
52 | ); 53 | }; 54 | 55 | render() { 56 | const style = { 57 | margin: 12 58 | }; 59 | 60 | return ( 61 |
62 |
{this.renderCategoryName()}
63 | 64 |
65 |
{this.renderQuestions()}
66 |
67 | 68 |
69 | 70 | 71 | 72 |
73 |
74 | ); 75 | } 76 | } 77 | 78 | function mapStateToProps(state) { 79 | return { category: state.category }; 80 | } 81 | 82 | export default withRouter(connect(mapStateToProps, { fetchQuestion })(Category)); 83 | -------------------------------------------------------------------------------- /src/client/components/Contributor/ContributorForm.js: -------------------------------------------------------------------------------- 1 | // REACT 2 | import React, { Component } from 'react'; 3 | import { Link } from 'react-router-dom'; 4 | 5 | // REDUX 6 | import { connect } from 'react-redux'; 7 | import { Field, reduxForm } from 'redux-form'; 8 | 9 | // MATERIAL UI 10 | import TextField from 'material-ui/TextField'; 11 | import { RadioButton, RadioButtonGroup } from 'material-ui/RadioButton'; 12 | import SelectField from 'material-ui/SelectField'; 13 | import MenuItem from 'material-ui/MenuItem'; 14 | 15 | // FILES 16 | import Category from '../Category/Category'; 17 | import './../../css/Contributor_Form.css'; 18 | 19 | // ACTION CREATOR 20 | import { createContribution } from './../../actions'; 21 | 22 | class ContributorForm extends Component { 23 | renderRadioGroup({ input, ...rest }) { 24 | return ( 25 |
26 | input.onChange(value)} 31 | /> 32 |
33 | ); 34 | } 35 | 36 | renderField(field) { 37 | const classNameDanger = `form-group ${ 38 | field.meta.touched && field.meta.error ? 'has-danger' : '' 39 | }`; 40 | return ( 41 |
42 | 43 | 44 |
45 | {field.meta.touched ? field.meta.error : ''} 46 | {/* this .meta.error property is automatically added to that field object from our validate function */} 47 |
48 |
49 | ); 50 | } 51 | 52 | onSubmit(values) { 53 | //if reduxform(handleSubmit) says that everything is valid... then call onSubmit 54 | console.log('onSubmit values=== ', values); 55 | console.log('=== CREATECONTRIBUTION === ', this.props.createContribution); 56 | 57 | this.props.createContribution(values, () => { 58 | this.props.history.push('/'); 59 | }); 60 | } 61 | 62 | render() { 63 | const handleSubmit = this.props.handleSubmit; 64 | 65 | const style = { 66 | display: 'flex', 67 | flexDirection: 'column', 68 | width: '100%' 69 | }; 70 | 71 | return ( 72 |
73 |
74 | 75 |
76 |
79 |
80 | {/* 81 | /////// 82 | /// RADIOBUTTON LEFT 83 | /////// 84 | */} 85 |
86 |
87 | 88 | 89 | 90 | 91 | 92 | 96 | 97 | 98 |
99 | 100 |
101 | 102 | 103 | 104 | 105 | 109 | 110 | 111 | 112 |
113 |
114 | 115 | {/* 116 | /////// 117 | /// RADIOBUTTON RIGHT 118 | /////// 119 | */} 120 |
121 |
122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 |
134 | 135 |
136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 |
148 |
149 |
150 | 151 |
152 | 153 | 154 |
155 | 156 |
157 | 158 | Back 159 | 160 | 163 |
164 |
165 |
166 | ); 167 | } 168 | } 169 | 170 | function validate(values) { 171 | const errors = {}; 172 | 173 | if (!values.topic) { 174 | errors.topic = 'Select a topic'; 175 | } 176 | if (!values.question) { 177 | errors.question = 'Enter a question'; 178 | } 179 | if (!values.answer) { 180 | errors.answer = 'Enter an answer'; 181 | } 182 | return errors; 183 | } 184 | 185 | export default reduxForm({ 186 | validate: validate, 187 | form: 'CreateNewQuestion' 188 | })(connect(null, { createContribution })(ContributorForm)); 189 | -------------------------------------------------------------------------------- /src/client/components/Landing/Landing.js: -------------------------------------------------------------------------------- 1 | // REACT 2 | import React, { Component } from 'react'; 3 | 4 | // FILES 5 | import LandingPageCategoryButtons from './landingPageCategoryButtons'; 6 | import GitHubLoginContainer from '../../containers/gitHubLoginContainer'; 7 | // import LandingContainer from '../../containers/landingContainer'; 8 | import GitHubLoginButton from './gitHubLoginButton'; 9 | import Navbar from './navbar'; 10 | 11 | class Landing extends Component { 12 | render() { 13 | return ( 14 |
15 | 16 |
17 | 18 | 19 | 20 |
21 |
22 | ); 23 | } 24 | } 25 | export default Landing; 26 | -------------------------------------------------------------------------------- /src/client/components/Landing/Login.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | class Login extends Component { 4 | render() { 5 | return
this is Category Page
; 6 | } 7 | } 8 | export default Login; 9 | -------------------------------------------------------------------------------- /src/client/components/Landing/gitHubLoginButton.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import RaisedButton from "material-ui/RaisedButton"; 3 | import FontIcon from "material-ui/FontIcon"; 4 | import GitHubLogin from "react-github-login"; 5 | import Keys from "../../../config/keys"; 6 | 7 | const onSuccess = res => console.log(res); 8 | const onFailure = res => console.log(res); 9 | 10 | const styles = { 11 | button: { 12 | margin: 12 13 | }, 14 | exampleImageInput: { 15 | cursor: "pointer", 16 | position: "absolute", 17 | top: 0, 18 | bottom: 0, 19 | right: 0, 20 | left: 0, 21 | width: "100%", 22 | opacity: 0 23 | } 24 | }; 25 | 26 | const GitHubLoginButton = () => ( 27 |
28 | 35 | } 41 | /> 42 | 43 |
44 | ); 45 | 46 | export default GitHubLoginButton; 47 | -------------------------------------------------------------------------------- /src/client/components/Landing/landingPageCategoryButtons.js: -------------------------------------------------------------------------------- 1 | // REACT 2 | import React, { Component } from 'react'; 3 | import { Link } from 'react-router-dom'; 4 | import { withRouter } from 'react-router'; 5 | 6 | // REDUX 7 | import { connect } from 'react-redux'; 8 | // ACTION CREATOR 9 | import { fetchQuestions } from './../../actions'; 10 | // MATERIAL UI & CSS 11 | import RaisedButton from 'material-ui/RaisedButton'; 12 | import '../../css/Landing.css'; 13 | 14 | const style = { 15 | margin: '12px auto', 16 | width: 300, 17 | height: 50, 18 | display: 'block' 19 | }; 20 | 21 | const nested_style = { 22 | margin: '12px auto', 23 | width: 250, 24 | height: 30, 25 | display: 'block' 26 | }; 27 | 28 | class LandingPageCategoryButtons extends Component { 29 | constructor(props) { 30 | super(props); 31 | } 32 | 33 | handleClick = e => { 34 | let topic = e.currentTarget.value; 35 | console.log('this is topic', topic); 36 | let allTopics = [ 37 | ['Algorithm', 'Sort', 'Recursion', 'Asymptomatic Notation', 'Data Structures'], 38 | [ 39 | 'System Design', 40 | 'Principles', 41 | 'System Design Patterns', 42 | 'Scalability', 43 | 'CAP Theorem' 44 | ], 45 | [ 46 | 'Front End', 47 | 'ReactJS', 48 | 'Angular', 49 | 'JavaScript', 50 | 'Vue', 51 | 'Ember', 52 | 'Redux', 53 | 'jQuery' 54 | ], 55 | ['Back End', 'Node/Express', 'PHP', '.NET', 'Ruby on Rails', 'SQL', 'NoSQL', 'Java'] 56 | ]; 57 | let category; 58 | let getCategoryIndex; 59 | 60 | for (let i = 0; i < allTopics.length; i++) { 61 | if (allTopics[i].includes(topic)) getCategoryIndex = i; 62 | } 63 | // console.log('this is getCategoryIndex', getCategoryIndex); 64 | switch (getCategoryIndex) { 65 | case 0: 66 | category = 'Algorithm'; 67 | break; 68 | case 1: 69 | category = 'System Design'; 70 | break; 71 | case 2: 72 | category = 'Front End'; 73 | break; 74 | case 3: 75 | category = 'Back End'; 76 | break; 77 | default: 78 | break; 79 | } 80 | 81 | this.props.fetchQuestions(category, topic).then(() => { 82 | this.props.history.push('/category'); 83 | }); 84 | 85 | // this.props.fetchQuestions(category, () => { 86 | // this.props.history.push('/category'); 87 | // }); 88 | }; 89 | 90 | render() { 91 | return ( 92 |
93 | {/* 94 | /////////// 95 | /// CATEGORY LEFT - ALGORITHM & SYSTEM DESIGN 96 | /////////// 97 | */} 98 |
99 | {/* ALGORITHM */} 100 |
101 | 108 |
109 | 116 | 123 | 130 | 137 |
138 |
139 | 140 | {/* FRONT END */} 141 |
142 | 149 |
150 | 157 | 164 | 171 | 178 | 185 | 192 | 199 |
200 |
201 |
202 | 203 | {/* 204 | /////////// 205 | /// CATEGORY RIGHT - FRONT-END & BACK-END 206 | /////////// 207 | */} 208 |
209 | {/* SYSTEM DESIGN */} 210 |
211 | 218 |
219 | 226 | 233 | 240 | 247 |
248 |
249 | 250 | {/* BACK END */} 251 |
252 | 259 |
260 | 267 | 274 | 281 | 288 | 295 | 302 | 309 |
310 |
311 |
312 |
313 | ); 314 | } 315 | } 316 | 317 | export default withRouter(connect(null, { fetchQuestions })(LandingPageCategoryButtons)); 318 | -------------------------------------------------------------------------------- /src/client/components/Landing/navbar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import AppBar from 'material-ui/AppBar'; 3 | import IconButton from 'material-ui/IconButton'; 4 | import NavigationClose from 'material-ui/svg-icons/navigation/close'; 5 | import FlatButton from 'material-ui/FlatButton'; 6 | import GitHubLoginButton from './gitHubLoginButton'; 7 | // import logo from './../../assets/logo.svg'; 8 | 9 | function handleClick() { 10 | alert('onClick triggered on the title component'); 11 | } 12 | 13 | const styles = { 14 | title: { 15 | cursor: 'pointer' 16 | }, 17 | gitHub: { 18 | backgroundColor: 'black' 19 | } 20 | }; 21 | 22 | const image_style = { 23 | height: '50px', 24 | width: 'auto' 25 | }; 26 | 27 | /** 28 | * This example uses an [IconButton](/#/components/icon-button) on the left, has a clickable `title` 29 | * through the `onClick` property, and a [FlatButton](/#/components/flat-button) on the right. 30 | */ 31 | const Navbar = () => ( 32 | 38 | } 39 | // onTitleClick={handleClick} 40 | // iconElementLeft={} 41 | iconElementRight={} 42 | /> 43 | ); 44 | 45 | export default Navbar; 46 | -------------------------------------------------------------------------------- /src/client/components/Questionnaire/AnswerPage.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import CategoryName from './categoryName'; 3 | import BackButton from './backButton'; 4 | import NextQuestionButton from './nextQuestionButton' 5 | import GetAnswerButton from './getAnswerButton'; 6 | import QuestionBox from './questionBox' 7 | import AnswerBox from './answerBox' 8 | 9 | 10 | class AnswerPage extends Component { 11 | render() { 12 | return
13 |
14 | 15 |
16 |
17 | 18 |
19 |
20 | 21 |
22 |
23 | 24 |
25 |
26 | 27 |
28 |
29 | } 30 | } 31 | 32 | const styles = { 33 | categoryName: { 34 | display: 'flex', 35 | justifyContent: 'center', 36 | }, 37 | backButton: { 38 | position: 'absolute', 39 | top: 810, 40 | left: 50, 41 | }, 42 | nextQuestionButton: { 43 | position: 'absolute', 44 | top: 810, 45 | left: 1390, 46 | }, 47 | answerBox: { 48 | position: 'absolute', 49 | top: 630, 50 | left: 320, 51 | }, 52 | questionBox: { 53 | position: 'absolute', 54 | top: 180, 55 | left: 320, 56 | } 57 | } 58 | export default AnswerPage; 59 | -------------------------------------------------------------------------------- /src/client/components/Questionnaire/QuestionPage.js: -------------------------------------------------------------------------------- 1 | // REACT 2 | import React, { Component } from 'react'; 3 | import { Link } from 'react-router-dom'; 4 | 5 | // REDUX 6 | import { connect } from 'react-redux'; 7 | 8 | // LODASH 9 | import _ from 'lodash'; 10 | 11 | // FILES 12 | import Paper from 'material-ui/Paper'; 13 | import NextQuestionButton from './nextQuestionButton'; 14 | import GetAnswerButton from './getAnswerButton'; 15 | import './../../css/Question_Page.css'; 16 | 17 | class QuestionPage extends Component { 18 | // const { category } = this.props; 19 | // const { question } = category; 20 | // const { answer } = category; 21 | // const { topic } = category; 22 | 23 | renderAnswer = () => { 24 | let answer_element = document.createElement('div'); 25 | answer_element.textContent = this.props.category.answer; 26 | document.querySelector('#answer').appendChild(answer_element); 27 | const btn = document.querySelector('#answer-btn'); 28 | document.querySelector('#remove-btn').removeChild(btn); 29 | }; 30 | 31 | render() { 32 | return ( 33 |
34 |
35 | {/* 36 | {this.props.category.category} 37 | */} 38 | 39 |
40 | {this.props.category.category} 41 |
42 |
43 | 44 |
45 | {/* 46 | {this.props.category.question} 47 | */} 48 | 49 |
50 | {this.props.category.question} 51 |
52 |
53 | 54 |
55 | 61 |
62 | 63 |
64 |
65 |
66 | 67 |
68 | 69 | Back 70 | 71 |
72 | 73 | {/*
74 | 75 |
*/} 76 |
77 | ); 78 | } 79 | } 80 | 81 | const style = { 82 | height: 410, 83 | width: 1000, 84 | margin: 20, 85 | textAlign: 'center', 86 | display: 'inline-block', 87 | color: 'black' 88 | }; 89 | 90 | const category_style = { 91 | height: 70, 92 | width: 700, 93 | margin: 20, 94 | textAlign: 'center', 95 | display: 'inline-block', 96 | color: 'black' 97 | }; 98 | 99 | function mapStateToProps(state) { 100 | return { category: state.category }; 101 | } 102 | 103 | export default connect(mapStateToProps)(QuestionPage); 104 | -------------------------------------------------------------------------------- /src/client/components/Questionnaire/answerBox.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Paper from 'material-ui/Paper'; 3 | 4 | const style = { 5 | height: 200, 6 | width: 1000, 7 | margin: 20, 8 | textAlign: 'center', 9 | display: 'inline-block', 10 | color: 'black' 11 | }; 12 | 13 | const AnswerBox = () => ( 14 |
15 | Random Answer 16 |
17 | ); 18 | 19 | export default AnswerBox; -------------------------------------------------------------------------------- /src/client/components/Questionnaire/backButton.js: -------------------------------------------------------------------------------- 1 | // import React from 'react'; 2 | // import RaisedButton from 'material-ui/RaisedButton'; 3 | 4 | // const style = { 5 | // margin: 12, 6 | // width: 200, 7 | // }; 8 | 9 | // const BackButton = () => ( 10 | //
11 | // 12 | //
13 | // ); 14 | 15 | // export default BackButton; 16 | -------------------------------------------------------------------------------- /src/client/components/Questionnaire/categoryName.js: -------------------------------------------------------------------------------- 1 | // import React from 'react'; 2 | // import Paper from 'material-ui/Paper'; 3 | 4 | // const style = { 5 | // height: 70, 6 | // width: 700, 7 | // margin: 20, 8 | // textAlign: 'center', 9 | // display: 'inline-block', 10 | // color: 'black' 11 | // }; 12 | 13 | // const CategoryName = () => ( 14 | //
15 | // Category Name 16 | //
17 | // ); 18 | 19 | // export default CategoryName; 20 | -------------------------------------------------------------------------------- /src/client/components/Questionnaire/getAnswerButton.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import RaisedButton from 'material-ui/RaisedButton'; 3 | 4 | const style = { 5 | margin: 12, 6 | width: 1000 7 | }; 8 | 9 | const GetAnswerButton = () => ( 10 |
11 | 12 |
13 | ); 14 | 15 | export default GetAnswerButton; 16 | -------------------------------------------------------------------------------- /src/client/components/Questionnaire/nextQuestionButton.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import RaisedButton from 'material-ui/RaisedButton'; 3 | 4 | const style = { 5 | margin: 12, 6 | width: 200, 7 | }; 8 | 9 | const NextQuestionButton = () => ( 10 |
11 | 12 |
13 | ); 14 | 15 | export default NextQuestionButton; -------------------------------------------------------------------------------- /src/client/components/Questionnaire/questionBox.js: -------------------------------------------------------------------------------- 1 | // import React from 'react'; 2 | // import Paper from 'material-ui/Paper'; 3 | 4 | // const style = { 5 | // height: 410, 6 | // width: 1000, 7 | // margin: 20, 8 | // textAlign: 'center', 9 | // display: 'inline-block', 10 | // color: 'black' 11 | // }; 12 | 13 | // const QuestionBox = () => ( 14 | //
15 | // 16 | //
17 | // ); 18 | 19 | // export default QuestionBox; 20 | -------------------------------------------------------------------------------- /src/client/containers/gitHubLoginContainer.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | export default class gitHubLoginContainer extends Component { 4 | render() { 5 | return
{this.props.children}
; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/client/containers/landingContainer.js: -------------------------------------------------------------------------------- 1 | // import React, { Component } from 'react'; 2 | 3 | // export default class gitHubLoginContainer extends Component { 4 | // render() { 5 | // return
{this.props.children}
; 6 | // } 7 | // } 8 | -------------------------------------------------------------------------------- /src/client/css/Contributor_Form.css: -------------------------------------------------------------------------------- 1 | .contributor-form-container { 2 | display: flex; 3 | flex-direction: column; 4 | } 5 | 6 | .contributor-message { 7 | text-align: center; 8 | } 9 | 10 | .form-container { 11 | display: flex; 12 | flex-direction: column; 13 | } 14 | 15 | .radiobutton-left { 16 | padding-top: 50px; 17 | display: flex; 18 | } 19 | 20 | .radiobutton-right { 21 | padding-top: 50px; 22 | padding-bottom: 20px; 23 | display: flex; 24 | } 25 | 26 | .radiobutton-algorithm { 27 | width: 50%; 28 | } 29 | 30 | .radiobutton-system-design { 31 | width: 50%; 32 | } 33 | 34 | .radiobutton-front-end { 35 | width: 50%; 36 | } 37 | 38 | .radiobutton-back-end { 39 | width: 50%; 40 | } 41 | 42 | .question-answer-container { 43 | display: flex; 44 | flex-direction: column; 45 | max-width: 100%; 46 | } 47 | 48 | .form-group { 49 | width: 60%; 50 | align-self: center; 51 | } 52 | 53 | .submit-back-btn-container { 54 | width: 60%; 55 | } 56 | 57 | .contributor-back-btn { 58 | float: left !important; 59 | } 60 | .contributor-submit-btn { 61 | float: right !important; 62 | } 63 | -------------------------------------------------------------------------------- /src/client/css/Landing.css: -------------------------------------------------------------------------------- 1 | *, 2 | ::after, 3 | ::before { 4 | -webkit-box-sizing: border-box; 5 | -moz-box-sizing: border-box; 6 | box-sizing: border-box; 7 | position: relative; 8 | } 9 | 10 | .fontawesome-i2svg-active { 11 | width: 100%; 12 | height: 100%; 13 | } 14 | 15 | #root { 16 | height: 100%; 17 | display: flex; 18 | flex-direction: column; 19 | } 20 | 21 | article, 22 | aside, 23 | details, 24 | figcaption, 25 | figure, 26 | footer, 27 | header, 28 | hgroup, 29 | main, 30 | menu, 31 | nav, 32 | section, 33 | summary { 34 | display: block; 35 | } 36 | 37 | body { 38 | font-family: Helvetica Neue, Helvetica, Arial, sans-serif; 39 | font-size: 16px; 40 | line-height: 1.5; 41 | color: #676e7b; 42 | background-color: #f7f7f7; 43 | margin: 0; 44 | height: 100%; 45 | } 46 | 47 | main { 48 | min-width: 500px; 49 | height: 100%; 50 | display: flex; 51 | flex-direction: column; 52 | justify-content: center; 53 | } 54 | 55 | .wrapper { 56 | height: 100%; 57 | } 58 | 59 | .landing-head-container { 60 | display: flex; 61 | height: 90%; 62 | width: 100%; 63 | flex-direction: row; 64 | justify-content: space-around; 65 | } 66 | 67 | #category-btn-container { 68 | /* margin-top: 128px; */ 69 | /* width: 50%; */ 70 | display: flex; 71 | order: 1; 72 | margin: auto; 73 | /* float: right; */ 74 | } 75 | 76 | .github-container { 77 | display: flex; 78 | border-right: 1px solid black; 79 | height: 100%; 80 | width: 50%; 81 | } 82 | 83 | .gitHubWrap { 84 | /* margin-top: 128px; */ 85 | /* width: 50%; */ 86 | display: flex; 87 | margin: auto; 88 | /* float: left; */ 89 | } 90 | 91 | .gitHubLogin { 92 | display: flex; 93 | padding: 0; 94 | border-width: 0px; 95 | border-style: none; 96 | border-color: transparent; 97 | background-color: transparent; 98 | } 99 | -------------------------------------------------------------------------------- /src/client/css/Question_Page.css: -------------------------------------------------------------------------------- 1 | .questionpage-container { 2 | height: 100%; 3 | width: 100%; 4 | display: flex; 5 | flex-direction: column; 6 | } 7 | 8 | .questionpage-category-container { 9 | text-align: center; 10 | display: inline-block; 11 | width: 700px; 12 | height: 70px; 13 | } 14 | 15 | .questionpage-category-paper { 16 | background: white; 17 | height: 100%; 18 | width: 100%; 19 | } 20 | 21 | .questionpage-question-container { 22 | text-align: center; 23 | display: inline-block; 24 | width: 100%; 25 | height: 400px; 26 | } 27 | 28 | .questionpage-question-paper { 29 | background: white; 30 | } 31 | 32 | .questionpage-answer-btn-container { 33 | width: 100%; 34 | /* height: 100%; */ 35 | text-align: center; 36 | } 37 | 38 | .questionpage-answer-btn { 39 | width: 50%; 40 | /* height: 50%; */ 41 | } 42 | 43 | .questionpage-answer-container { 44 | background: white; 45 | width: 80%; 46 | text-align: center; 47 | height: 100px; 48 | } 49 | 50 | .questionpage-answer { 51 | position: relative; 52 | top: 50%; 53 | } 54 | 55 | .questionpage-back-btn-container { 56 | width: 100%; 57 | margin-left: 37px; 58 | } 59 | 60 | .questionpage-back-btn { 61 | width: 120px; 62 | } 63 | -------------------------------------------------------------------------------- /src/client/css/general.css: -------------------------------------------------------------------------------- 1 | /* body { 2 | background-color: lightgray 3 | } */ 4 | -------------------------------------------------------------------------------- /src/client/index.js: -------------------------------------------------------------------------------- 1 | // REACT 2 | import React from 'react'; 3 | import ReactDOM from 'react-dom'; 4 | import { BrowserRouter } from 'react-router-dom'; 5 | 6 | // REDUX 7 | import { Provider } from 'react-redux'; 8 | import { createStore, applyMiddleware } from 'redux'; 9 | import reduxThunk from 'redux-thunk'; 10 | import promise from 'redux-promise'; 11 | 12 | // MATERIAL UI 13 | 14 | import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'; 15 | 16 | 17 | // FILES 18 | import App from './components/App'; 19 | import reducers from './reducers'; 20 | 21 | const store = applyMiddleware(reduxThunk)(createStore); //Redux Store 22 | // const store = createStore(reducers, {}, applyMiddleware(reduxThunk)); 23 | 24 | ReactDOM.render( 25 | 26 | {/* "Provider": react component that knows how to read changes from the redux store anytime the redux store gets some new state and then will update all its children with the changed state */} 27 | 28 | 29 | 30 | 31 | 32 | , 33 | document.getElementById('root') 34 | ); 35 | -------------------------------------------------------------------------------- /src/client/reducers/category_reducer.js: -------------------------------------------------------------------------------- 1 | import { FETCH_QUESTIONS, FETCH_QUESTION } from './../actions/types'; 2 | import _ from 'lodash'; 3 | 4 | export default function(state = {}, action) { 5 | //REDUCER 6 | switch (action.type) { 7 | case FETCH_QUESTIONS: 8 | return _.map(action.payload); 9 | 10 | case FETCH_QUESTION: 11 | return action.payload; 12 | 13 | default: 14 | return state; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/client/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import { reducer as formReducer } from 'redux-form'; 3 | import CategoryReducer from './category_reducer'; 4 | 5 | const rootReducer = combineReducers({ 6 | form: formReducer, 7 | category: CategoryReducer 8 | }); 9 | 10 | export default rootReducer; 11 | -------------------------------------------------------------------------------- /src/client/reducers/question_answer.js: -------------------------------------------------------------------------------- 1 | // import { FETCH_QUESTION } from './../actions/types'; 2 | // import _ from 'lodash'; 3 | 4 | // export default function(state = {}, action) { 5 | // //REDUCER 6 | // switch (action.type) { 7 | // case FETCH_QUESTION: 8 | // return _.map(action.playload); 9 | 10 | // default: 11 | // return state; 12 | // } 13 | // } 14 | -------------------------------------------------------------------------------- /src/config/keys.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | mongoURI: 3 | "mongodb://thecodinggym:cs19@ds129796.mlab.com:29796/the-coding-gym", 4 | // googleClientID: //INSERT GITHUB ID & KEYS 5 | // '380358937727-p9i36pah8vgnipaqku2gntejanah2sje.apps.googleusercontent.com', 6 | // googleClientSecret: 'vqBPv_4nHJ7l3P_H8qkthWbi', 7 | // cookieKey: 'fjkldajflakjfopbinaidfjeapfdapinviadnsfjpaijfdpj' 8 | githubID: "7793c95e193ad6cbf9b5", 9 | githubSecret: "f557ac3461eb3e83e1df07832c9ee68ee55f5c50" 10 | }; 11 | -------------------------------------------------------------------------------- /src/server/model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const Schema = mongoose.Schema; 3 | 4 | const QandASchema = new Schema({ 5 | category: String, 6 | topic: String, 7 | question: String, 8 | answer: String 9 | }); 10 | 11 | module.exports = mongoose.model('QandA', QandASchema); -------------------------------------------------------------------------------- /src/server/routers.js: -------------------------------------------------------------------------------- 1 | // import { ActionQuestionAnswer } from 'material-ui'; 2 | 3 | const express = require('express'); 4 | const request = require('request'); 5 | const router = express.Router(); 6 | const QandA = require('./model.js'); 7 | 8 | router.use((req, res, next) => { 9 | console.log('this workig hereee'); 10 | next(); 11 | }); 12 | router.get('/', (req, res) => { 13 | //on the api route localhost3000/api 14 | console.log('in here'); 15 | res.json({ message: 'welcome to our api!' }); 16 | }); 17 | 18 | router 19 | .route('/questions') 20 | .post((req, res) => { 21 | let qAndA = new QandA(); 22 | console.log(req.body, 'this is the post method here'); // create a new instance of the model 23 | qAndA.category = req.body.category; 24 | qAndA.topic = req.body.topic; 25 | qAndA.question = req.body.question; // set the question coming from the request 26 | qAndA.answer = req.body.answer; // set the answer coming from the request 27 | qAndA.save(err => { 28 | if (err) { 29 | res.send(err); 30 | } else { 31 | let selectedTopic = req.body.topic; 32 | let selectedCategory = req.body.category; 33 | // console.log( 34 | // 'this is selectedTopic: ', 35 | // selectedTopic, 36 | // ' and this is the selectedCategory: ', 37 | // selectedCategory 38 | // ); 39 | if (selectedTopic === selectedCategory) { 40 | //USER SELECTED GENERAL CATEGORY AS TOPIC 41 | QandA.find({ category: selectedCategory }, (err, question) => { 42 | // console.log('this the question returned in back', question); 43 | let results = []; 44 | for (let i = 0; i < question.length; i++) { 45 | let quest = question[i].question; 46 | let ans = question[i].answer; 47 | if (quest && ans) { 48 | results.push(question[i]); 49 | } 50 | } 51 | res.json({ 52 | results 53 | }); 54 | }); 55 | } else { 56 | //USER WANTS SPECIFIC QUESTION TOPICS 57 | QandA.find({ topic: selectedTopic }, (err, question) => { 58 | // console.log( 59 | // 'this the question returned in back when a specific topic is selected', 60 | // question 61 | // ); 62 | let results = []; 63 | for (let i = 0; i < question.length; i++) { 64 | let quest = question[i].question; 65 | let ans = question[i].answer; 66 | if (quest && ans) { 67 | results.push(question[i]); 68 | } 69 | } 70 | res.json({ 71 | results 72 | }); 73 | }); 74 | } 75 | } 76 | }); 77 | }) 78 | .get((req, res) => { 79 | // console.log(req.data, 'cateogry!!!!'); 80 | QandA.find(req.params.questions_id, (err, question) => { 81 | (err, question) => { 82 | console.log('we here in get'); 83 | // console.log('this is data from get api side', question); 84 | // let category = question.category; 85 | // let questionList = question.question; 86 | if (err) { 87 | res.send(err); 88 | console.log('got an err'); 89 | } 90 | // if (req.body.category === category) { //NEED TO MODIFY DEPENDING ON HOW API CALL IS MADE ON FRONT END 91 | // res.json(questionList); //send all algo questions 92 | // } else { 93 | // console.log('are we in here') 94 | res.json(question); 95 | }; 96 | }); 97 | }); 98 | router 99 | .route('/questions/:id') //route added to get question by ID 100 | .get((req, res) => { 101 | QandA.findById(req.params.id, (err, question) => { 102 | if (err) { 103 | res.send(err); 104 | console.log('got an err up in hurr'); 105 | } 106 | res.json(question); 107 | }); 108 | }) 109 | .put((req, res) => { 110 | //route to update question 111 | QandA.findById(req.params.questions_id, (err, question) => { 112 | if (err) { 113 | res.send(err); 114 | console.log('got an err up in hurr in the put route'); 115 | } 116 | question.answer = req.body.answer; //updates the answer 117 | question.save(err => { 118 | if (err) res.send(err); 119 | res.json({ message: 'answer updated!' }); 120 | }); 121 | }); 122 | }) 123 | .delete((req, res) => { 124 | QandA.remove( 125 | { 126 | _id: req.params.questions_id 127 | }, 128 | (err, question) => { 129 | if (err) res.send(err); 130 | res.json({ message: 'successfully deleted' }); 131 | } 132 | ); 133 | }); 134 | 135 | router.all('*', (req, res, next) => { 136 | err = new Error('router.js - default catch all route - not found'); 137 | err.status = 404; 138 | next(err); 139 | }); 140 | 141 | module.exports = router; 142 | -------------------------------------------------------------------------------- /src/server/server.js: -------------------------------------------------------------------------------- 1 | // REQUIRE 2 | const path = require('path'); 3 | const bodyParser = require('body-parser'); 4 | const cookieParser = require('cookie-parser'); 5 | 6 | // EXPRESS 7 | const express = require('express'); 8 | const app = express(); 9 | app.use(bodyParser.urlencoded({ extended: true })); 10 | app.use(bodyParser.json()); 11 | 12 | // MONGOOSE 13 | const mongoose = require('mongoose'); 14 | const keys = require('../config/keys.js'); 15 | mongoose.connect(keys.mongoURI); 16 | mongoose.connection.once('open', () => { 17 | console.log('^^^^^^CONNECTED TO THE DATABASE^^^^^'); 18 | }); 19 | 20 | // API ROUTING 21 | const routers = require('./routers'); 22 | // COOKIES 23 | app.use(cookieParser('process.env.COOKIE_SECRET')); 24 | // PATH FOR STATIC FILES 25 | app.use(express.static(`${__dirname}./../../`)); 26 | 27 | // app.use('/api', router); 28 | app.use('/api', routers); 29 | // ERROR HANDLING 30 | app.use((err, req, res, next) => { 31 | res.status(404).end('error') 32 | }) 33 | 34 | app.use('/css', express.static(path.join(__dirname, './../client/css'))); 35 | app.get('*', (req, res) => { 36 | res.sendFile(path.join(__dirname, './../../index.html')); 37 | }); 38 | 39 | 40 | const PORT = process.env.PORT || 3000; 41 | 42 | app.listen(PORT, () => console.log('******SERVER LISTENING ON PORT 3000******')); 43 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const BUILD_DIR = path.resolve(__dirname, './build'); 4 | const APP_DIR = path.resolve(__dirname, './src/client'); 5 | 6 | const config = { 7 | entry: { 8 | main: ['babel-polyfill', `${APP_DIR}/index.js`] 9 | }, 10 | output: { 11 | filename: 'bundle.js', 12 | path: BUILD_DIR 13 | }, 14 | module: { 15 | rules: [ 16 | { 17 | test: /\.(jsx|js)?$/, 18 | use: [ 19 | { 20 | loader: 'babel-loader', 21 | options: { 22 | cacheDirectory: true, 23 | presets: ['react', 'es2015', 'stage-3', 'stage-2', 'stage-0'] // Transpiles JSX and ES6 24 | } 25 | } 26 | ] 27 | }, 28 | { 29 | test: /.css$/, 30 | use: ['style-loader', 'css-loader'] 31 | }, 32 | { test: /\.(png|jpg|jpeg|gif|svg)$/, loader: 'url-loader?limit=100000' } 33 | ] 34 | }, 35 | resolve: { 36 | extensions: ['.js', '.jsx'] 37 | } 38 | }; 39 | 40 | module.exports = config; 41 | --------------------------------------------------------------------------------