From 65e4aa5630d69234f0e1a1b7d756667ac4ee273b Mon Sep 17 00:00:00 2001 From: souravtecken Date: Sun, 1 Sep 2019 13:35:37 +0530 Subject: [PATCH 1/6] Restructure front end for new course/assignment/signup flow. 1. Added signup option in the navbar dropdown. 2. Seperated courseCards for courseAdmin/(Student/CourseMember) 3. Seperated courseView pages for the same. 4. Added requestCourse option in courses page. 5. courseMember can add assignments within a courseCard. 6. Added professor list reducer (For retrieving list of teaching members in courseAdminCard) Course component hierarchy: - CoursesContainer (Conditional renders either of the following two views) - CoursesAdminView (contains handleApproveCourse, handleRejectCourse methods) - CourseCardAdmin (Card for course request) - CourseView (contains handleActivateCourse, handleRequestCourse methods) - CourseCard (Card for teaching members/student, contains handleCreateAssignment method) profReducer: - Action: FETCHED_PROFS - adds list of teacher objects (containing ID and name) to store. - Action: CLEARED_PROFS - Clears teachers from store. --- client/app/components/Layout/Navbar.js | 18 +- .../Pages/Assignments/Assignments.js | 256 ++++++------ .../components/Pages/Courses/CourseCard.js | 70 ---- .../Pages/Courses/CourseCards/CourseCard.js | 379 ++++++++++++++++++ .../Courses/CourseCards/CourseCardAdmin.js | 198 +++++++++ .../components/Pages/Courses/CourseView.js | 231 +++++++++++ .../app/components/Pages/Courses/Courses.js | 329 --------------- .../Pages/Courses/CoursesAdminView.js | 170 ++++++++ .../Pages/Courses/CoursesContainer.js | 62 +++ client/app/components/Signup/Signup.js | 78 ++++ client/app/index.js | 9 +- client/app/reducers/index.js | 4 +- client/app/reducers/profReducer.js | 12 + 13 files changed, 1279 insertions(+), 537 deletions(-) delete mode 100644 client/app/components/Pages/Courses/CourseCard.js create mode 100644 client/app/components/Pages/Courses/CourseCards/CourseCard.js create mode 100644 client/app/components/Pages/Courses/CourseCards/CourseCardAdmin.js create mode 100644 client/app/components/Pages/Courses/CourseView.js delete mode 100644 client/app/components/Pages/Courses/Courses.js create mode 100644 client/app/components/Pages/Courses/CoursesAdminView.js create mode 100644 client/app/components/Pages/Courses/CoursesContainer.js create mode 100644 client/app/components/Signup/Signup.js create mode 100644 client/app/reducers/profReducer.js diff --git a/client/app/components/Layout/Navbar.js b/client/app/components/Layout/Navbar.js index 6687389..6f77c67 100644 --- a/client/app/components/Layout/Navbar.js +++ b/client/app/components/Layout/Navbar.js @@ -27,7 +27,7 @@ class NavbarClass extends Component { constructor() { super(); this.state = { - signInUsn: "", + signInEmail: "", signInpassword: "", loginShow: true, navbarIsOpen: false @@ -35,7 +35,7 @@ class NavbarClass extends Component { this.toggle = this.toggle.bind(this); this.onSignIn = this.onSignIn.bind(this); - this.onTextboxChangeSignInUsn = this.onTextboxChangeSignInUsn.bind(this); + this.onTextboxChangeSignInEmail = this.onTextboxChangeSignInEmail.bind(this); this.onTextboxChangeSignInPassword = this.onTextboxChangeSignInPassword.bind(this); }; @@ -52,10 +52,10 @@ class NavbarClass extends Component { } - onTextboxChangeSignInUsn(event) { + onTextboxChangeSignInEmail(event) { event.preventDefault(); this.setState({ - signInUsn: event.target.value, + signInEmail: event.target.value, }); } @@ -63,7 +63,7 @@ class NavbarClass extends Component { onSignIn(event) { event.preventDefault(); const user = { - usn: this.state.signInUsn, + email: this.state.signInEmail, password: this.state.signInPassword }; @@ -137,8 +137,8 @@ class NavbarClass extends Component { diff --git a/client/app/components/Pages/Assignments/Assignments.js b/client/app/components/Pages/Assignments/Assignments.js index 8ac7ac2..41cdd07 100644 --- a/client/app/components/Pages/Assignments/Assignments.js +++ b/client/app/components/Pages/Assignments/Assignments.js @@ -5,133 +5,135 @@ import AssignmentCard from './AssignmentCard'; import ReactLoading from './../../common/Loading'; class Assignments extends Component { - constructor(props) { - super(props); - this.state = { - isLoading: true, - courses: [], - role: "student", - assignments: [] - }; - } - componentDidMount() { - var self = this; - var token = localStorage.getItem('token'); - var userID = localStorage.getItem('user_id'); + constructor(props) { + super(props); + this.state = { + isLoading: true, + courses: [], + role: "student", + assignments: [] + }; + } + componentDidMount() { + var self = this; + var token = localStorage.getItem('token'); + var userID = localStorage.getItem('user_id'); - var apiPath = '/api/account/' + userID + '/details' - axios.get(apiPath, { - headers: { - 'x-access-token': token, - 'Content-Type': 'application/json' - } - }) - .then(function (response) { - if (!response.data.success) { - // TODO: throw appropriate error and redirect - console.log("Error1: " + response.data); - return; - } - var data = response.data; - self.setState({ - role: data.user.role - }); - }) - .catch(function (error) { - console.log(error); - if (error.response) { - if (error.response.status) { - alert("Session timed out."); - window.location.href = '/'; - } - } - }); - var apiPath = '/api/assignments/' + userID + '/courses' - axios.get(apiPath, { - headers: { - 'x-access-token': token, - 'Content-Type': 'application/json' - } - }) - .then(function (response) { - if (!response.data.success) { - // TODO: throw appropriate error and redirect - console.log("Error1: " + response.data); - - } - var data = response.data; - // console.log(data); - self.setState({ isLoading: false }); - self.setState({ - courses: data.courses - }); - var courses = data.courses; - for (var i = 0; i < courses.length; i++) { - var apiPath = '/api/assignments/' + courses[i]._id + '/' + userID + '/new'; - axios.get(apiPath, { - headers: { - 'x-access-token': token, - 'Content-Type': 'application/json' - } - }) - .then(function (response) { - if (!response.data.success) { - console.log("Error1: " + response.data); - } - var data = response.data; - self.setState({ - assignments: self.state.assignments.concat(data.assignments.assignments) - }); - console.log(response.data); - }) - .catch(function (error) { - console.log('Error2: ', error); - }); - }// End of for loop - }) - } - render() { - let content; - const profContent = ( -
- { - this.state.assignments.length < 1 && -
Sorry, no assignments found.
- } - { - this.state.assignments.map(function (each) { - return - }) - } -
Home
-
- ); - const studContent = ( -
- { - this.state.assignments.length < 1 && -
Sorry, no new assignments found.
- } - { - this.state.assignments.map(function (each) { - return - }) - } -
Home
-
- ); - if (this.state.role == "prof") { - content = profContent; - } - else { - content = studContent; - } - if (this.state.isLoading) - return ; - else - return ( -
{content}
- ); - } + var apiPath = '/api/account/' + userID + '/details' + axios.get(apiPath, { + headers: { + 'x-access-token': token, + 'Content-Type': 'application/json' + } + }) + .then(function (response) { + if (!response.data.success) { + // TODO: throw appropriate error and redirect + console.log("Error1: " + response.data); + return; + } + var data = response.data; + self.setState({ + role: data.user.role + }); + }) + .catch(function (error) { + console.log(error); + if (error.response) { + if (error.response.status) { + alert("Session timed out."); + window.location.href = '/'; + } + } + }); + var apiPath = '/api/assignments/' + userID + '/courses'; + axios.get(apiPath, { + headers: { + 'x-access-token': token, + 'Content-Type': 'application/json' + } + }) + .then(function (response) { + if (!response.data.success) { + // TODO: throw appropriate error and redirect + console.log("Error1: " + response.data); + + } + var data = response.data; + // console.log(data); + self.setState({ isLoading: false }); + self.setState({ + courses: data.courses + }); + var courses = data.courses; + for (var i = 0; i < courses.length; i++) { + var apiPath = '/api/assignments/' + courses[i]._id + '/' + userID + '/new'; + axios.get(apiPath, { + headers: { + 'x-access-token': token, + 'Content-Type': 'application/json' + } + }) + .then(function (response) { + if (!response.data.success) { + console.log("Error1: " + response.data); + } + var data = response.data; + self.setState({ + assignments: self.state.assignments.concat(data.assignments.assignments) + }); + console.log(response.data); + }) + .catch(function (error) { + console.log('Error2: ', error); + }); + }// End of for loop + }) + } + + render() { + let content; + const profContent = ( +
+ { + this.state.assignments.length < 1 && +
Sorry, no assignments found.
+ } + { + this.state.assignments.map(function (each) { + return + }) + } + +
+ ); + const studContent = ( +
+ { + this.state.assignments.length < 1 && +
Sorry, no new assignments found.
+ } + { + this.state.assignments.map(function (each) { + return + }) + } + +
+ ); + if (this.state.role == "prof") { + content = profContent; + } + else { + content = studContent; + } + if (this.state.isLoading) + return ; + else + return ( +
{content}
+ ); + } } + export default Assignments; \ No newline at end of file diff --git a/client/app/components/Pages/Courses/CourseCard.js b/client/app/components/Pages/Courses/CourseCard.js deleted file mode 100644 index 6acf08c..0000000 --- a/client/app/components/Pages/Courses/CourseCard.js +++ /dev/null @@ -1,70 +0,0 @@ -import React, { Component } from 'react'; -import { Link, Redirect } from 'react-router-dom'; - -class CourseCard extends Component { - constructor(props) { - super(props); - this.state = { - courseID: '' - }; - } - componentDidMount() { - this.setState({ - courseID: this.props.courseID - }) - } - - - render() { - let content; - const profContent = ( -
-
-

{this.props.code}: {this.props.name}

-
- Credits: {this.props.credits}
- Deparment: {this.props.department}
- Description: {this.props.description}
- Resource URL: {this.props.resourceUrl} -
-
- View Course -
-
-
-
- ); - const studContent = ( -
-
-

{this.props.code}: {this.props.name}

-
- Credits: {this.props.credits}
- Deparment: {this.props.department}
- Description: {this.props.description}
- Resource URL: {this.props.resourceUrl} -
-
-
-
- ); - if (this.props.role == "prof") { - content = profContent; - } - else { - content = studContent; - } - return ( -
{content}
- ) - } -} - -export default CourseCard; diff --git a/client/app/components/Pages/Courses/CourseCards/CourseCard.js b/client/app/components/Pages/Courses/CourseCards/CourseCard.js new file mode 100644 index 0000000..341da19 --- /dev/null +++ b/client/app/components/Pages/Courses/CourseCards/CourseCard.js @@ -0,0 +1,379 @@ +import React, { Component } from 'react'; +import { Link, Redirect } from 'react-router-dom'; +import { Input, InputGroup, InputGroupAddon, Collapse, Button, CardBody, Card, Badge, Table } from 'reactstrap'; +import { ToastContainer, ToastStore } from 'react-toasts'; +import axios from 'axios'; +import {Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'; +import {connect} from 'react-redux'; + +class CourseCard extends Component { + constructor(props) { + super(props); + this.state = { + courseID: '', + collapse: false, + course:null, + showModal:false + }; + this.toggle = this.toggle.bind(this); + this.handleInputChange = this.handleInputChange.bind(this); + this.handleDetailsChange = this.handleDetailsChange.bind(this); + this.handleDurationChange = this.handleDurationChange.bind(this); + this.toggleCreateAssignment = this.toggleCreateAssignment.bind(this); + this.handleCreateAssignment = this.handleCreateAssignment.bind(this); + } + // Create Assignment Handler + handleCreateAssignment(event){ + event.preventDefault(); + const self = this; + const createAssignmentFormElements = event.target.getElementsByTagName("input"); + var apiPath = `/api/assignments/${this.props.auth.user_id}/createAssignment` + const token = this.props.auth.token; + const config = { + headers: { + 'x-access-token': token, + 'Content-Type': 'application/json' + } + } + const data = {}; + data.courseID = this.state.courseID; + data.name = createAssignmentFormElements["assignmentName"].value; + data.uniqueId = createAssignmentFormElements["assignmentID"].value; + data.type = createAssignmentFormElements["assignmentType"].value; + data.details = createAssignmentFormElements["assignmentDetails"].value; + data.maxMarks = createAssignmentFormElements["assignmentMaxMarks"].value; + data.resourcesUrl = createAssignmentFormElements["assignmentResources"].value; + data.duration = {}; + data.duration.startDate = createAssignmentFormElements["assignmentStartDate"].value; + data.duration.endDate = createAssignmentFormElements["assignmentEndDate"].value; + console.log(data); + axios.post(apiPath, data, config) + .then(res => { + console.log(res.data); + ToastStore.success(res.data.message); + setTimeout(() => {self.reload()},2000); + }) + .catch(err => { + console.log(err.response.data.message); + ToastStore.error(err.response.data.message); + }) + + } + // Generalised input handler for form inputs + handleInputChange(event) { + const updatedCourse = this.state.course; + updatedCourse[event.target.name] = event.target.value; + this.setState({ + course: updatedCourse + }) + } + // Handler for start and end date inputs + handleDurationChange(event) { + const updatedCourse = this.state.course; + updatedCourse["duration"][event.target.name] = event.target.value; + this.setState({ + course: updatedCourse + }) + } + // Handler for course details input + handleDetailsChange(event) { + const updatedCourse = this.state.course; + console.log(updatedCourse); + updatedCourse["details"][event.target.name] = Number(event.target.value); + this.setState({ + course: updatedCourse + }) + } + reload() { + window.location.reload() + } + toggle() { // For reactstrap Collapse component + this.setState(state => ({ collapse: !state.collapse })); + } + toggleCreateAssignment() { // For create assignment modal + this.setState(state => ({ showModal: !state.showModal})); + } + componentWillMount() { // Add pre-defined course attributes, and other values to course object in state before mounting + const course = this.props.course; + if(!course.hasOwnProperty("duration")){ + course["duration"]={}; + } + this.setState({ + courseID: this.props.course._id, + course: Object.assign({}, course) + }) + } + + render() { + const course = this.props.course; + const self = this; + var createCourseModal = null; + // For courses pending activation by a courseMember + if(this.props.course.validated === true && this.props.course.active === false){ + var courseGlance = ( +
+
+
+
+
Course Code
+

{course.code}

+
+
+
+
+
Course Name
+

{course.name}

+
+
+
+
+
Department
+

{course.department}

+
+
+
+ Pending Activation +
+
+ +
+ ) + var courseDetails = ( + + + +
+
Course Name*
+ +
+
+
Code*
+ +
+
+
Department*
+ +
+
+
Graduating Year*
+ +
+
+
Description*
+ +
+
+
Hours*
+ +
+
+
Credits*
+ +
+
+
+ + +
+
+ + +
+
+ +
+ {' '} +
+
+ ); + } + // For activated courses + else { + var courseGlance; + // If user is a course member (Add assignment available) + if(this.props.course.class.teachingMembers.find( teachingMember => teachingMember.teacher === self.props.userid)){ + courseGlance = ( +
+
+
+
+
Course Code
+

{course.code}

+
+
+
+
+
Course Name
+

{course.name}

+
+
+
+
+
Department
+

{course.department}

+
+
+
+ +
+
+ +
+ ) + // Modal view to create an assignment under a course + createCourseModal = ( + + Create Assignment + +
+
+
Course Name*
+ +
+
+
Code*
+ +
+
+
Assignment Name*
+ +
+
+
Assignment ID*
+ +
+
+
Type*
+ +
+
+
Details*
+ +
+
+
Maximum Marks*
+ +
+
+
Resources
+ +
+
+
+ + +
+
+ + +
+
+ +
+
+ + + +
+ ) + } + // If user is not a course member (Add assignment not available) + else { + courseGlance = ( +
+
+
+
+
Course Code
+

{course.code}

+
+
+
+
+
Course Name
+

{course.name}

+
+
+
+
+
Department
+

{course.department}

+
+
+
+ +
+ ) + } + + var courseDetails = ( + + +
+
+
Course Name
+

{this.state.course.name}

+
+
+
Code
+

{this.state.course.code}

+
+
+
Department
+

{this.state.course.department}

+
+
+
Graduating Year
+

{this.state.course.graduatingYearOfStudents}

+
+
+
Description
+

{this.state.course.description}

+
+
+
Hours
+

{this.state.course.details.hours}

+
+
+
Credits
+

{this.state.course.details.credits}

+
+
+
+
Start Date
+

{this.state.course.duration.startDate}

+
+
+
End Date
+

{this.state.course.duration.endDate}

+
+
+
+
+
+ ); + } + + return ( +
+ {createCourseModal} + + + {courseGlance} + + {courseDetails} + + + + +
+ ) + } +} + +const mapStateToProps = (state) => { + return { + auth:state.auth + } +} +export default connect(mapStateToProps)(CourseCard); diff --git a/client/app/components/Pages/Courses/CourseCards/CourseCardAdmin.js b/client/app/components/Pages/Courses/CourseCards/CourseCardAdmin.js new file mode 100644 index 0000000..d3f2a26 --- /dev/null +++ b/client/app/components/Pages/Courses/CourseCards/CourseCardAdmin.js @@ -0,0 +1,198 @@ +import React, { Component } from 'react'; +import { Link, Redirect } from 'react-router-dom'; +import { Input, InputGroup, InputGroupAddon, Collapse, Button, CardBody, Card, Badge, Table } from 'reactstrap'; +import axios from 'axios'; +import {connect} from 'react-redux'; + +class CourseCardAdmin extends Component { + constructor(props) { + super(props); + this.state = { + courseID: '', + collapse: false, + course:null, + }; + this.toggle = this.toggle.bind(this); + this.handleInputChange = this.handleInputChange.bind(this); + this.handleSectionsChange = this.handleSectionsChange.bind(this); + this.removeSelectedTeacher = this.removeSelectedTeacher.bind(this); + } + handleSearch(event){ + const searchElement = event.target.value; + const professorListElements = document.getElementsByClassName("professorListElement"); + for(const professorElement of professorListElements){ + if(professorElement.getAttribute("profname").search(searchElement) != -1 || searchElement==="") + professorElement.style.display = "table-row"; + else + professorElement.style.display = "none"; + } + } + handleInputChange(event) { + const updatedCourse = this.state.course; + updatedCourse[event.target.name] = event.target.value; + this.setState({ + course: updatedCourse + }) + } + handleSectionsChange(event) { + const sectionsInput = event.target.value; + const updatedCourse = this.state.course; + updatedCourse.class.sections = sectionsInput.split(","); + updatedCourse.class.sections.map(section => { + if(section) + return section.trim(); + }); + this.setState({ + course: updatedCourse + }) + } + toggle() { // For reactstrap Collapse component + this.setState(state => ({ collapse: !state.collapse })); + } + selectTeacher(professor){ + const course = this.state.course; + const updatedSelectedTeachers = course.class.teachingMembers; + if(updatedSelectedTeachers.findIndex(item => item.teacher === professor) <0){ + updatedSelectedTeachers.push({teacher:professor}); + this.setState({course}); + } + } + removeSelectedTeacher(event){ + const course = this.state.course; + const indexToBeRemoved = course.class.teachingMembers.findIndex(teachingMember => teachingMember.teacher === event.target.id); + if(indexToBeRemoved >= 0){ + course.class.teachingMembers.splice(indexToBeRemoved, 1); + this.setState({ + course + }); + } + } + + componentWillMount() { + this.setState({ + courseID: this.props.course._id, + course: Object.assign({}, this.props.course) + }) + } + + render() { + const self = this; + const course = this.props.course; + const selectedTeachers = this.state.course.class.teachingMembers.map((teachingMember) => { + const teacherName = self.props.professors[teachingMember.teacher]; + return( + {teacherName.firstName+" "+teacherName.lastName} + ) + }) + if(this.props.professors){ + var teachersList = Object.keys(this.props.professors).map((professorId) => { + const profName = this.props.professors[professorId].firstName+" "+this.props.professors[professorId].lastName; + return( + + {profName} + {' '} + + ) + }) + } + const teacherSelector = ( +
+ + Search + + +
+ + + {teachersList} + +
+
+
+ ) + + var courseGlance = ( +
+
+
+
+
Course Code
+

{course.code}

+
+
+
+
+
Course Name
+

{course.name}

+
+
+
+
+
Department
+

{course.department}

+
+
+
+ Pending Approval +
+
+ +
+ ) + var courseDetails = ( + + +
+
+
Course Name*
+ +
+
+
Code*
+ +
+
+
Department*
+ +
+
+
Graduating Year*
+ +
+
+
Sections* (Comma seperated)
+ +
+
+
Teachers*
+ {selectedTeachers} + {teacherSelector} +
+
+
+ {' '} + +
+
+ ); + return ( +
+ + + {courseGlance} + + {courseDetails} + + + +
+ ) + } +} + +const mapStateToProps = (state) => { + return{ + professors:state.profs.professors + } +} +export default connect(mapStateToProps)(CourseCardAdmin); diff --git a/client/app/components/Pages/Courses/CourseView.js b/client/app/components/Pages/Courses/CourseView.js new file mode 100644 index 0000000..badb177 --- /dev/null +++ b/client/app/components/Pages/Courses/CourseView.js @@ -0,0 +1,231 @@ +import React, { Component } from 'react'; +import axios from 'axios'; +import { Link, Redirect } from 'react-router-dom'; +import { ToastContainer, ToastStore } from 'react-toasts'; +import CourseCard from './CourseCards/CourseCard'; +import AnchorForm from './AnchorForm'; +import ReactLoading from '../../common/Loading'; + +class CoursesView extends Component { + constructor(props) { + super(props); + this.state = { + isLoading:true, + role: '', + tags: [], + courses: [], + showRequestCourse: false, + }; + this.handleRequestCourse = this.handleRequestCourse.bind(this); + this.handleActivateCourse = this.handleActivateCourse.bind(this); + this.toggleRequestCourse = this.toggleRequestCourse.bind(this); + } + handleActivateCourse(course){ + const apiPath = '/api/assignments/'+ course._id + '/createValidatedCourse'; + const token = localStorage.getItem('token'); + const config = { + headers: { + 'x-access-token': token, + } + } + axios.put(apiPath, course, config) + .then(res=>{ + console.log(res); + ToastStore.success(res.data.message); + }) + .catch(err=>{ + console.log(err); + ToastStore.error(err.response.data.message); + }) + } + handleRequestCourse(event) { + event.preventDefault(); + const self = this; + const token = localStorage.getItem('token'); + const apiPath = 'api/assignments/requestCourse'; + const config = { + headers: { + 'x-access-token': token, + 'Content-Type': 'application/json' + } + } + const requestCourseFormElements = event.target.getElementsByTagName("input"); + const data = Object.assign({}, self.state.course); + data.name = requestCourseFormElements["name"].value; + data.code = requestCourseFormElements["code"].value; + data.department = requestCourseFormElements["department"].value; + data.role = this.state.role; + axios.post(apiPath, data, config) + .then(res => { + console.log(res.data); + ToastStore.success(res.data.message); + setTimeout(() => {self.reload()},3000); + }) + .catch(err => { + console.log(err); + ToastStore.error(err.response.data.message); + }) + } + reload() { + window.location.reload() + } + toggleRequestCourse() { + this.setState({ + showRequestCourse: !this.state.showRequestCourse + }) + } + componentDidMount() { + var self = this; + var userID = localStorage.getItem('user_id'); + var token = localStorage.getItem('token') + + var apiPath = '/api/account/' + userID + '/details' + axios.get(apiPath, { + headers: { + 'x-access-token': token, + } + }) + .then(function (response) { + if (!response.data.success) { + // TODO: throw appropriate error and redirect + console.log("Error1: " + response.data); + return; + } + var data = response.data; + self.setState({ + _id: data.user._id, + role: data.user.role, + tags: data.user.tags + }); + }) + .catch(function (error) { + console.log(error); + if (error.response) { + if (error.response.status) { + alert("Session timed out."); + window.location.href = '/'; + } + } + }); + ///api/assignments/:userID/getValidatedCourses + apiPath = 'api/assignments/' + userID + '/getValidatedCourses' + axios.get(apiPath, { + headers: { + 'x-access-token': token, + 'Content-Type': 'application/json' + } + }) + .then(function (response) { + if (!response.data.success) { + console.log("Error1: " + response.data); + } + self.setState({ + isLoading: false, + }) + const courses = response.data.courses; + if(courses){ + self.setState({ + courses: self.state.courses.concat(response.data.courses) + }); + } + console.log(response.data); + }) + .catch(function (error) { + console.log('Error2: ', error); + }); + + apiPath = 'api/assignments/' + userID + '/courses' + axios.get(apiPath, { + headers: { + 'x-access-token': token, + 'Content-Type': 'application/json' + } + }) + .then(function (response) { + if (!response.data.success) { + console.log("Error1: " + response.data); + } + self.setState({ + isLoading: false, + }) + const courses = response.data.courses; + if(courses){ + self.setState({ + courses: self.state.courses.concat(response.data.courses) + }); + } + }) + .catch(function (error) { + console.log('Error2: ', error); + }); + } + render() { + const requestCourseForm = ( +
+

Request Course

+
+
+
+
Course Name*
+ +
+
+
Code*
+ +
+
+
Department*
+ +
+
+ + +
+
+ ) + let courses = ( +
+
Sorry, no courses found.
+ +
+ ) + if(this.state.courses.length){ + const self = this; + courses = this.state.courses.map(function (course) { + return ( + + + ) + }) + } + const content = ( +
+
+
+ {courses} +
+
+
+
+
+ {this.state.showRequestCourse ? null : } + {this.state.showRequestCourse ? requestCourseForm : null} +
+
+
+ +
+ ); + + if (this.state.isLoading) + return ; + else + return
{content}
+ } +} + +export default CoursesView; diff --git a/client/app/components/Pages/Courses/Courses.js b/client/app/components/Pages/Courses/Courses.js deleted file mode 100644 index 765b6cf..0000000 --- a/client/app/components/Pages/Courses/Courses.js +++ /dev/null @@ -1,329 +0,0 @@ -import React, { Component } from 'react'; -import axios from 'axios'; -import { Link, Redirect } from 'react-router-dom'; -import CourseCard from '../Courses/CourseCard'; -import AnchorForm from './AnchorForm'; -import ReactLoading from './../../common/Loading'; - -class CoursesAdd extends Component { - constructor(props) { - super(props); - this.state = { - isLoading: true, - role: '', - name: '', - code: '', - department: '', - description: '', - resourcesUrl: '', - startDate: '', - endDate: '', - credits: '', - hours: '', - isCore: '', - courses: [], - profRole: '', - professorID: '', - classes: [], - sections: '', - graduating: '', - anchorDescription: '', - show: false, - }; - this.onAdd = this.onAdd.bind(this); - this.showForm = this.showForm.bind(this); - this.closeForm = this.closeForm.bind(this); - this.chooseProfRole = this.chooseProfRole.bind(this); - this.chooseAnchorRole = this.chooseAnchorRole.bind(this); - this.handleInputChange = this.handleInputChange.bind(this); - this.handleCreditsChange = this.handleCreditsChange.bind(this); - this.handleHoursChange = this.handleHoursChange.bind(this); - } - - componentDidMount() { - - var self = this; - var userID = localStorage.getItem('user_id'); - var token = localStorage.getItem('token') - - var apiPath = '/api/account/' + userID + '/details' - axios.get(apiPath, { - headers: { - 'x-access-token': token, - } - }) - .then(function (response) { - if (!response.data.success) { - // TODO: throw appropriate error and redirect - console.log("Error1: " + response.data); - return; - } - var data = response.data; - self.setState({ - role: data.user.role - }); - }) - .catch(function (error) { - console.log(error); - if (error.response) { - if (error.response.status) { - alert("Session timed out."); - window.location.href = '/'; - } - } - }); - ///api/assignments/:userID/courses - var apiPath = 'api/assignments/' + userID + '/courses' - axios.get(apiPath, { - headers: { - 'x-access-token': token, - 'Content-Type': 'application/json' - } - }).then(function (response) { - if (!response.data.success) { - console.log("Error1: " + response.data); - } - var data = response.data; - self.setState({ isLoading: false }); - self.setState({ - courses: self.state.courses.concat(data.courses) - }); - console.log(response.data); - }) - .catch(function (error) { - console.log('Error2: ', error); - }); - } - handleInputChange(e) { - this.setState({ - [e.target.name]: e.target.value - }) - } - - handleCreditsChange(e) { - this.setState({ - credits: e.target.value - }) - } - handleHoursChange(e) { - this.setState({ - hours: e.target.value - }) - } - reload() { - window.location.reload() - } - - onAdd() { - ///api/courses/createCourse - var self = this; - var userID = localStorage.getItem('user_id'); - var token = localStorage.getItem('token'); - var apiPath = 'api/assignments/createCourse'; - var config = { - headers: { - 'x-access-token': token, - 'Content-Type': 'application/json' - } - } - var data = Object.assign({}, self.state.course); - - data.name = self.state.name; - data.code = self.state.code; - data.department = self.state.department; - data.description = self.state.description; - data.resourcesUrl = self.state.resourcesUrl; - var details = { credits: self.state.credits, hours: self.state.hours, isCore: self.state.isCore } - data.details = details; - var duration = { startDate: self.state.startDate, endDate: self.state.endDate } - data.duration = duration; - data.graduating = self.state.graduating; - if ("prof".localeCompare(self.state.profRole) == 0) { - data.professorID = self.state.professorID; - data.sections = self.state.sections - data.role = 'prof'; - console.log(data); - axios.post(apiPath, data, config) - .then(res => { - console.log(res.data); - this.reload(); - }) - .catch(err => { - console.log(err); - alert('Course Failed to Upload!') - }) - } - } - showForm() { - this.setState({ - show: true - }) - } - closeForm() { - this.setState({ - show: false, - profRole: '' - }) - } - chooseProfRole() { - this.setState({ - profRole: 'prof' - }) - } - chooseAnchorRole() { - this.setState({ - profRole: 'anchor' - }) - } - - - render() { - let content; - const chooseRole = ( -
- - -
- ) - - const professorBoxes = ( -
-
Sections*
- -
Professor*
- -
- ) - - const anchorBoxes = ( -
- -
- ) - - const anchorDescription = ( -
-
Anchor Description
-