From 7853b1b183995286bc915b66a632526d9b06e041 Mon Sep 17 00:00:00 2001 From: Roosted7 <thomasroos@live.nl> Date: Sat, 24 Mar 2018 12:02:29 +0100 Subject: [PATCH] Beginning of grade page --- client/index.jsx | 2 +- client/views/Grade.jsx | 133 ++++++++++++++++++++++-- client/views/grade/EditPanel.jsx | 135 +++++++++++++++++++++++++ client/views/grade/FeedbackPanel.jsx | 66 ++++++++++++ client/views/grade/ProblemSelector.jsx | 47 +++++++++ client/views/grade/ProgessBar.jsx | 0 6 files changed, 373 insertions(+), 10 deletions(-) create mode 100644 client/views/grade/EditPanel.jsx create mode 100644 client/views/grade/FeedbackPanel.jsx create mode 100644 client/views/grade/ProblemSelector.jsx create mode 100644 client/views/grade/ProgessBar.jsx diff --git a/client/index.jsx b/client/index.jsx index dc605ac01..3fd4a711d 100644 --- a/client/index.jsx +++ b/client/index.jsx @@ -111,7 +111,7 @@ class App extends React.Component { <Route path="/students" render={() => <Students exam={exam} /> }/> <Route path="/grade" render={() => ( - exam && exam.submissions ? <Grade /> : <Fail message="No exams uploaded. Please do not bookmark URLs" /> + exam && exam.submissions ? <Grade exam={exam}/> : <Fail message="No exams uploaded. Please do not bookmark URLs" /> )} /> <Route path="/statistics" render={() => ( exam && exam.submissions ? <Statistics /> : <Fail message="No exams uploaded. Please do not bookmark URLs" /> diff --git a/client/views/Grade.jsx b/client/views/Grade.jsx index b994ef7a4..ee52d11b3 100644 --- a/client/views/Grade.jsx +++ b/client/views/Grade.jsx @@ -2,17 +2,132 @@ import React from 'react'; import Hero from '../components/Hero.jsx'; -const Grade = () => { - return ( - <div> +import FeedbackPanel from './grade/FeedbackPanel.jsx'; +import ProblemSelector from './grade/ProblemSelector.jsx'; +import EditPanel from './grade/EditPanel.jsx'; +const ProgressBar = () => null; - <Hero title='Grade' subtitle='This is where the magic happens!' /> - - <h1>React Router demo</h1> - Hoi dit de Grade +class Grade extends React.Component { - </div> - ) + state = { + editActive: false, + editFeedback: null, + problem: null, + submission: { + input: "", + imagePath: "" + }, + solution: null + } + + prev = () => { + + } + next = () => { + + } + + prevUngraded = () => { + + } + nextUngraded = () => { + + } + + toggleEdit = () => { + this.setState({ + editActive: !this.state.editActive, + editFeedback: null + }) + } + editFeedback = (event) => { + console.log(event); + this.setState({ + editActive: true + }) + } + + setSubInput = (event) => { + this.setState({ + submission: { + ...this.state.submission, + input: event.target.value + } + }) + } + setSubmission = () => { + + } + changeProblem = (id) => { + console.log(id); + this.setState({ + problem: id + }) + } + + + render() { + + + + return ( + <div> + + <Hero title='Grade' subtitle='This is where the magic happens!' /> + + <section className="section"> + + <div className="container"> + <div className="columns"> + <div className="column is-one-quarter-desktop is-one-third-tablet"> + <ProblemSelector examID={this.props.exam.id} changeProblem={this.changeProblem}/> + {this.state.editActive ? + <EditPanel problem={this.state.problem} feedbackID={this.state.editFeedback} toggleEdit={this.toggleEdit}/> + : + <FeedbackPanel problem={this.state.problem} toggleEdit={this.toggleEdit} + editFeedback={this.editFeedback}/> + } + </div> + + <div className="column"> + <div className="level"> + <div className="level-item"> + <div className="field has-addons is-mobile"> + <div className="control"> + <button type="submit" className="button is-info is-rounded is-hidden-mobile" + onClick={this.prevUngraded}>ungraded</button> + <button type="submit" className="button is-link" + onClick={this.prev}>Previous</button> + </div> + <div className="control"> + <input className="input is-rounded has-text-centered is-link" + value={this.state.submission.input} type="text" + onChange={this.setSubInput} onSubmit={this.setSubmission}/> + </div> + <div className="control"> + <button type="submit" className="button is-link" + onClick={this.next}>Next</button> + <button type="submit" className="button is-info is-rounded is-hidden-mobile" + onClick={this.nextUngraded}>ungraded</button> + </div> + </div> + </div> + </div> + + <ProgressBar submissions={this.state.submission} /> + + <p className="box"> + <img src={this.state.submission.imagePath} alt="" /> + </p> + + </div> + </div> + </div> + </section> + + </div> + ) + } } export default Grade; \ No newline at end of file diff --git a/client/views/grade/EditPanel.jsx b/client/views/grade/EditPanel.jsx new file mode 100644 index 000000000..f6ec6837f --- /dev/null +++ b/client/views/grade/EditPanel.jsx @@ -0,0 +1,135 @@ +import React from 'react'; + +import * as api from '../../api.jsx'; +import { startOfToday } from 'date-fns'; + + +const BackButton = (props) => ( + <button className="button is-light is-fullwidth" onClick={props.onClick}> + <span className="icon is-small"> + <i className="fa fa-chevron-left"></i> + </span> + <span>back</span> + </button> +) + +const SaveButton = (props) => ( + <button className="button is-link is-fullwidth" disabled={props.disabled} onClick={props.onClick}> + <span className="icon is-small"> + <i className="fa fa-floppy-o"></i> + </span> + <span>{props.exists ? "edit" : "add"}</span> + </button> +) + +class EditPanel extends React.Component { + + state = { + name: "", + description: "", + score: "" + } + + componentWillMount = () => { + if (this.props.feedback) { + const stud = this.props.editStud; + this.setState({ + id: stud.id, + firstName: stud.firstName, + lastName: stud.lastName, + email: stud.email + }) + } + } + + + changeName = (event) => { + this.setState({ + name: event.target.value + }) + } + changeDesc = (event) => { + this.setState({ + description: event.target.value + }) + } + changeScore = (event) => { + this.setState({ + score: event.target.value + }) + } + + + saveFeedback = () => { + + if (this.props.feedback) { + + } else { + api.post('feedback/' + this.props.problem, this.state) + .then(feedback => { + console.log(feedback) + this.props.toggleEdit(); + }) + } + } + + + render() { + + return ( + <nav className="panel"> + <p className="panel-heading"> + Manage feedback + </p> + + <div className="panel-block"> + <div className="field"> + <label className="label">Name</label> + <div className="control has-icons-left"> + <input className="input" placeholder="Name" + value={this.state.name} onChange={this.changeName} /> + <span className="icon is-small is-left"> + <i className="fa fa-quote-left"></i> + </span> + </div> + </div> + </div> + + <div className="panel-block"> + <div className="field"> + <label className="label">Description</label> + <div className="control has-icons-left"> + <input className="input" placeholder="Description" + value={this.state.description} onChange={this.changeDesc} /> + <span className="icon is-small is-left"> + <i className="fa fa-quote-right"></i> + </span> + </div> + + </div> + </div> + + <div className="panel-block"> + <div className="field"> + <label className="label">Score</label> + <div className="control has-icons-left has-icons-right"> + <input className="input" placeholder="Score" + value={this.state.score} onChange={this.changeScore} /> + <span className="icon is-small is-left"> + <i className="fa fa-envelope"></i> + </span> + </div> + </div> + </div> + + <div className="panel-block"> + <BackButton onClick={this.props.toggleEdit} /> + <SaveButton onClick={this.saveFeedback} disabled={!this.state.name} exists={this.props.feedback} /> + </div> + </nav> + ) + } +} + +export default EditPanel; + diff --git a/client/views/grade/FeedbackPanel.jsx b/client/views/grade/FeedbackPanel.jsx new file mode 100644 index 000000000..4d05507a7 --- /dev/null +++ b/client/views/grade/FeedbackPanel.jsx @@ -0,0 +1,66 @@ +import React from 'react'; + +import * as api from '../../api.jsx' + +const FeedbackBlock = (props) => ( + <a className="panel-block is-active" onClick={props.onClick} > + <span className="panel-icon"> + <i className={"fa fa-" + (props.checked ? "check-square-o" : "square-o")}></i> + </span> + {props.feedback.name} <i>- [{props.feedback.score}]</i> + </a> +) + + +class FeedbackPanel extends React.Component { + + state = { + feedback: [] + } + + componentDidMount = () => { + if (this.props.problem) { + api.get('feedback/' + this.props.problem) + .then(feedback => { + this.setState({ + feedback: feedback + }) + }) + } + } + + componentWillReceiveProps = (nextProps) => { + if (this.props.problem !== nextProps.problem) { + api.get('feedback/' + nextProps.problem) + .then(feedback => { + this.setState({ + feedback: feedback + }) + }) + } + } + + render() { + + return ( + <nav className="panel"> + <p className="panel-heading"> + Feedback + </p> + {this.state.feedback.map((feedback, i) => + <FeedbackBlock key={i} index={i} feedback={feedback} checked={true} onClick={this.props.editFeedback} /> + )} + <div className="panel-block is-hidden-mobile"> + <button className="button is-link is-outlined is-fullwidth" onClick={this.props.toggleEdit}> + <span className="icon is-small"> + <i className="fa fa-plus"></i> + </span> + <span>add option</span> + </button> + </div> + </nav> + ) + } + +} +export default FeedbackPanel; \ No newline at end of file diff --git a/client/views/grade/ProblemSelector.jsx b/client/views/grade/ProblemSelector.jsx new file mode 100644 index 000000000..3614c932b --- /dev/null +++ b/client/views/grade/ProblemSelector.jsx @@ -0,0 +1,47 @@ +import React from 'react'; + +import * as api from '../../api.jsx' + +class ProblemSelector extends React.Component { + + state = { + problemList: [] + } + + componentDidMount = () => { + api.get('problems/' + this.props.examID) + .then(problems => { + this.setState({ + problemList: problems + }, this.props.changeProblem(problems[0].id)) + }) + + } + + render() { + return ( + <div className="field"> + <label className="label">Problem:</label> + <div className="control has-icons-left"> + <div className="select is-fullwidth"> + <select value={this.props.name} + onChange={(event) => this.props.changeProblem(event.target.value)}> + {this.state.problemList.map(problem => + <option key={problem.id} value={problem.id}>{problem.name}</option> + )} + + </select> + </div> + <span className="icon is-left"> + <i className="fa fa-question"></i> + </span> + <br /> + </div> + </div> + ) + } + + +} + +export default ProblemSelector; \ No newline at end of file diff --git a/client/views/grade/ProgessBar.jsx b/client/views/grade/ProgessBar.jsx new file mode 100644 index 000000000..e69de29bb -- GitLab