Skip to content
Snippets Groups Projects
Commit 52a3528b authored by jtimotei's avatar jtimotei
Browse files

Added the PanelMCQ component

parent b2e9f795
No related branches found
No related tags found
1 merge request!14Add boxes frontend
import React from 'react'
class PanelMCQ extends React.Component {
constructor (props) {
super(props)
this.onChangeNPA = this.onChangeNPA.bind(this)
this.onChangeLabelType = this.onChangeLabelType.bind(this)
this.generateLabels = this.generateLabels.bind(this)
this.state = {
chosenLabelType: 0,
nrPossibleAnswers: 2,
labelTypes: ['None', 'True/False', 'A, B, C ...', '1, 2, 3 ...']
}
}
onChangeNPA (e) {
let value = parseInt(e.target.value)
if (!isNaN(value)) {
this.setState({
nrPossibleAnswers: value
})
}
}
onChangeLabelType (e) {
let value = parseInt(e.target.value)
if (!isNaN(value)) {
this.setState({
chosenLabelType: value
})
if (parseInt(value) === 1) {
this.setState({
nrPossibleAnswers: 2
})
}
}
}
generateLabels (nrLabels) {
let type = this.state.chosenLabelType
switch (type) {
case 1:
return ['True', 'False']
case 2:
return Array.from(Array(nrLabels).keys()).map((e) => String.fromCharCode(e + 65))
case 3:
return Array.from(Array(nrLabels).keys()).map(e => e + 1)
default:
return Array(nrLabels).fill(' ')
}
}
render () {
return (
<nav className='panel'>
<p className='panel-heading'>
Multiple Choice Question
</p>
<div className='panel-block'>
<div className='field'>
<React.Fragment>
<label className='label'>Number possible answers</label>
<div className='control'>
{(function () {
var optionList = []
for (var i = 1; i <= this.props.totalNrAnswers; i++) {
const optionElement = <option key={i} value={String(i)}>{i}</option>
optionList.push(optionElement)
}
return (<div className='select is-hovered is-fullwidth'>
<select value={this.state.nrPossibleAnswers} onChange={this.onChangeNPA}>{optionList}</select>
</div>)
}.bind(this)())}
</div>
</React.Fragment>
</div>
</div>
<div className='panel-block'>
<div className='field'>
<React.Fragment>
<label className='label'>Answer boxes labels</label>
<div className='control'>
<div className='select is-hovered is-fullwidth'>
{(function () {
var optionList = this.state.labelTypes.map(
(label, i) => <option key={i} value={String(i)}>{label}</option>
)
return (
<div className='select is-hovered is-fullwidth'>
<select value={this.state.chosenLabelType} onChange={this.onChangeLabelType}>
{optionList}
</select>
</div>
)
}.bind(this)())}
</div>
</div>
</React.Fragment>
</div>
</div>
<div className='panel-block'>
<button
disabled={this.props.disabledGenerateBoxes}
className='button is-info is-fullwidth'
onClick={() => {
let npa = this.state.nrPossibleAnswers
let labels = this.generateLabels(npa)
this.props.onGenerateBoxesClick(npa, labels)
}}
>
Generate boxes
</button>
</div>
</nav>
)
}
}
export default PanelMCQ
client/components/answer_box.png

205 B

:root {
--option-width:13px;
--label-font-size:15px;
}
div.mc_option {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
justify-content: center;
align-items:center;
width:var(--option-width, 13px);
}
div.mc_option_label {
font-size: var(--label-font-size, 15px);
font-family: 'Helvetica', 'Arial', sans-serif;
}
.editor-content {
background-color: #ddd;
border-radius: 10px
......
......@@ -6,10 +6,14 @@ import Hero from '../components/Hero.jsx'
import './Exam.css'
import GeneratedExamPreview from '../components/GeneratedExamPreview.jsx'
import PanelGenerate from '../components/PanelGenerate.jsx'
import PanelMCQ from '../components/PaneMCQ.jsx'
import ExamEditor from './ExamEditor.jsx'
import update from 'immutability-helper'
import ExamFinalizeMarkdown from './ExamFinalize.md'
import ConfirmationModal from '../components/ConfirmationModal.jsx'
// FIXME!
// eslint-disable-next-line import/no-webpack-loader-syntax
import answerBoxImageSize from '!image-dimensions-loader!../components/answer_box.png'
import * as api from '../api.jsx'
......@@ -100,6 +104,19 @@ class Exams extends React.Component {
}))
}
createNewWidget = (widgetData) => {
this.setState((prevState) => {
return {
selectedWidgetId: widgetData.id,
widgets: update(prevState.widgets, {
[widgetData.id]: {
$set: widgetData
}
})
}
})
}
deleteWidget = (widgetId) => {
const widget = this.state.widgets[widgetId]
if (widget) {
......@@ -164,18 +181,7 @@ class Exams extends React.Component {
selectedWidgetId: widgetId
})
}}
createNewWidget={(widgetData) => {
this.setState((prevState) => {
return {
selectedWidgetId: widgetData.id,
widgets: update(prevState.widgets, {
[widgetData.id]: {
$set: widgetData
}
})
}
})
}}
createNewWidget={this.createNewWidget}
/>
)
}
......@@ -234,6 +240,18 @@ class Exams extends React.Component {
})
}
generateAnswerBoxes = () => {
// const widgetData = {
// x: 50,
// y: 50,
// id: 50,
// page: 0,
// name: 'mcq_widget',
// label: 'A'
// }
// this.createNewWidget(widgetData)
}
SidePanel = (props) => {
const selectedWidgetId = this.state.selectedWidgetId
let selectedWidget = selectedWidgetId && this.state.widgets[selectedWidgetId]
......@@ -241,7 +259,7 @@ class Exams extends React.Component {
let widgetEditDisabled = this.state.previewing || !problem
let isGraded = problem && problem.graded
let widgetDeleteDisabled = widgetEditDisabled || isGraded
let totalNrAnswers = 20 // the upper limit for the nr of possible answer boxes
let totalNrAnswers = 12 // the upper limit for the nr of possible answer boxes
let disabledGenerateBoxes = false
return (
......@@ -269,14 +287,14 @@ class Exams extends React.Component {
}}
saveProblemName={this.saveProblemName}
/>
<this.PanelMCQ
totalNrAnswers={totalNrAnswers}
disabledGenerateBoxes={disabledGenerateBoxes}
problem={problem}
onGenerateBoxesClick={() => {
console.log('Generating boxes')
}}
/>
{ this.state.selectedWidgetId == null ? null : (
<PanelMCQ
totalNrAnswers={totalNrAnswers}
disabledGenerateBoxes={disabledGenerateBoxes}
problem={problem}
onGenerateBoxesClick={this.generateAnswerBoxes}
/>
)}
<this.PanelExamActions />
</React.Fragment>
)
......@@ -293,7 +311,7 @@ class Exams extends React.Component {
<div className='panel-block'>
<div className='field'>
{selectedWidgetId === null ? (
<p style={{margin: '0.625em 0', minHeight: '3em'}}>
<p style={{ margin: '0.625em 0', minHeight: '3em' }}>
To create a problem, draw a rectangle on the exam.
</p>
) : (
......@@ -310,7 +328,8 @@ class Exams extends React.Component {
}}
onBlur={(e) => {
props.saveProblemName(e.target.value)
}} />
}}
/>
</div>
</React.Fragment>
)}
......@@ -330,46 +349,6 @@ class Exams extends React.Component {
)
}
PanelMCQ = (props) => {
const selectedWidgetId = this.state.selectedWidgetId
return selectedWidgetId == null ? null : (
<nav className='panel'>
<p className='panel-heading'>
Multiple Choice Question
</p>
<div className='panel-block'>
<div className='field'>
<React.Fragment>
<label className='label'>Number possible answers</label>
<div className='control'>
{(function () {
var optionList = []
for (var i = 1; i <= props.totalNrAnswers; i++) {
const optionElement = <option value={String(i)}>{i}</option>
optionList.push(optionElement)
}
return (<div className='select is-info is-fullwidth'>
<select>{optionList}</select>
</div>)
}())}
</div>
</React.Fragment>
</div>
</div>
<div className='panel-block'>
<button
disabled={props.disabledGenerateBoxes}
className='button is-info is-fullwidth'
onClick={() => props.onGenerateBoxesClick()}
>
Generate boxes
</button>
</div>
</nav>
)
}
PanelExamActions = () => {
if (this.props.exam.finalized) {
return <PanelGenerate examID={this.state.examID} />
......
......@@ -8,6 +8,10 @@ import studentIdExampleImage from '../components/student_id_example.png'
// FIXME!
// eslint-disable-next-line import/no-webpack-loader-syntax
import studentIdExampleImageSize from '!image-dimensions-loader!../components/student_id_example.png'
import answerBoxImage from '../components/answer_box.png'
// FIXME!
// eslint-disable-next-line import/no-webpack-loader-syntax
import answerBoxImageSize from '!image-dimensions-loader!../components/answer_box.png'
import EmptyPDF from '../components/EmptyPDF.jsx'
import PDFOverlay from '../components/PDFOverlay.jsx'
......@@ -169,12 +173,34 @@ class ExamEditor extends React.Component {
}
}
renderMCWidget(labels) {
const element = (
<div>
</div>
)
}
renderMCOption (label) {
const element = (
<div className='mc_option widget selected'>
<div className='mc_option_label'>
{label}
</div>
<img src={answerBoxImage} />
</div>
)
return element
}
renderWidgets = () => {
// Only render when numPage is set
if (this.props.numPages !== null && this.props.widgets) {
const widgets = this.props.widgets.filter(widget => {
if (widget.name === 'student_id_widget' ||
widget.name === 'barcode_widget') {
widget.name === 'barcode_widget' ||
widget.name === 'mcq_widget') {
return !this.props.finalized
} else if (widget.problem) {
return widget.problem.page === this.props.page
......@@ -199,6 +225,9 @@ class ExamEditor extends React.Component {
/>
)
enableResizing = true
} else if (widget.name === 'mcq_widget') {
enableResizing = false
view = this.renderMCWidget(widget.labels)
} else {
let image
if (widget.name === 'barcode_widget') {
......
File deleted
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment