Skip to content

Commit 6e93ec9

Browse files
remo5000ning-y
authored andcommitted
Add MCQ option display for MCQ Questions (#128)
* Add question prop for workspace Also made the questions in IAssessment more specific * Add mock MCQ display for MCQQuestion * Decouple editorValue from editorContainer It must now be passed as a prop. The parent that spawns an EditorContainer can take care of the value. * Simplify WorkspaceProps * Add MCQChooser * Arrange content of MCQChooser * Style components to look consistent * Add mcq question to MCQChooser * Add word wrapping * Make buttons colored * Move mcqChooser scss into workspace * Format and add tests * Fix some CSS issues (#131) * Bump version 0.1.0 -> 0.1.1
1 parent 9184621 commit 6e93ec9

File tree

12 files changed

+124
-24
lines changed

12 files changed

+124
-24
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"private": true,
33
"name": "cadet-frontend",
4-
"version": "0.1.0",
4+
"version": "0.1.1",
55
"scripts-info": {
66
"format": "Format source code",
77
"start": "Start the Webpack development server",

src/components/Playground.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,20 @@ import WorkspaceContainer from '../containers/workspace'
99
import { sourceChapters } from '../reducers/states'
1010
import { SideContentTab } from './workspace/side-content'
1111

12-
export type PlaygroundProps = RouteComponentProps<{}>
12+
export interface IPlaygroundProps extends RouteComponentProps<{}> {
13+
editorValue: string
14+
}
1315

1416
type PlaygroundState = {
1517
isGreen: boolean
1618
}
1719

18-
class Playground extends React.Component<PlaygroundProps, PlaygroundState> {
20+
class Playground extends React.Component<IPlaygroundProps, PlaygroundState> {
1921
private keyMap = { goGreen: 'h u l k' }
2022

2123
private handlers = { goGreen: () => {} }
2224

23-
constructor(props: PlaygroundProps) {
25+
constructor(props: IPlaygroundProps) {
2426
super(props)
2527
this.state = { isGreen: false }
2628
this.handlers.goGreen = this.toggleIsGreen.bind(this)
@@ -36,6 +38,7 @@ class Playground extends React.Component<PlaygroundProps, PlaygroundState> {
3638
<WorkspaceContainer
3739
libQuery={parseLibrary(this.props)}
3840
prgrmQuery={parsePrgrm(this.props)}
41+
editorValue={this.props.editorValue}
3942
sideContentTabs={[playgroundIntroduction]}
4043
/>
4144
</HotKeys>
@@ -47,13 +50,13 @@ class Playground extends React.Component<PlaygroundProps, PlaygroundState> {
4750
}
4851
}
4952

50-
const parsePrgrm = (props: PlaygroundProps) => {
53+
const parsePrgrm = (props: IPlaygroundProps) => {
5154
const qsParsed = qs.parse(props.location.hash)
5255
// legacy support
5356
return qsParsed.lz !== undefined ? qsParsed.lz : qsParsed.prgrm
5457
}
5558

56-
const parseLibrary = (props: PlaygroundProps) => {
59+
const parseLibrary = (props: IPlaygroundProps) => {
5760
const libQuery = qs.parse(props.location.hash).lib
5861
const lib = libQuery === undefined ? NaN : parseInt(libQuery, 10)
5962
return sourceChapters.includes(lib) ? lib : undefined

src/components/__tests__/Playground.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import Playground from '../Playground'
66

77
test('Playground renders correctly', () => {
88
const props = {
9-
...mockRouterProps('/academy', {})
9+
...mockRouterProps('/academy', {}),
10+
editorValue: 'Test value'
1011
}
1112
const app = <Playground {...props} />
1213
const tree = shallow(app)

src/components/__tests__/__snapshots__/Playground.tsx.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
exports[`Playground renders correctly 1`] = `
44
"<HotKeys className=\\"Playground pt-dark\\" keyMap={{...}} handlers={{...}}>
5-
<Connect(Workspace) libQuery={[undefined]} prgrmQuery={[undefined]} sideContentTabs={{...}} />
5+
<Connect(Workspace) libQuery={[undefined]} prgrmQuery={[undefined]} editorValue=\\"Test value\\" sideContentTabs={{...}} />
66
</HotKeys>"
77
`;

src/components/assessment/assessmentShape.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export interface IProgrammingQuestion extends IQuestion {
4141
}
4242

4343
export interface IMCQQuestion extends IQuestion {
44-
choices?: MCQChoice[]
44+
choices: MCQChoice[]
4545
type: 'mcq'
4646
}
4747

src/components/assessment/index.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ import * as React from 'react'
55
import Workspace from '../../containers/workspace'
66
import { history } from '../../utils/history'
77
import { assessmentCategoryLink } from '../../utils/paramParseHelpers'
8+
import { OwnProps as WorkspaceProps } from '../workspace'
89
import { OwnProps as ControlBarOwnProps } from '../workspace/ControlBar'
910
import { SideContentTab } from '../workspace/side-content'
10-
import { IAssessment } from './assessmentShape'
11+
import { IAssessment, IMCQQuestion, IProgrammingQuestion } from './assessmentShape'
1112

1213
export type AssessmentProps = DispatchProps & OwnProps & StateProps
1314

@@ -61,7 +62,7 @@ class Assessment extends React.Component<AssessmentProps, { showOverlay: boolean
6162
const shortSummaryElement = (
6263
<Text> {this.props.assessment.questions[this.props.questionId].content} </Text>
6364
)
64-
const tabs: SideContentTab[] = [
65+
const sideContentTabs: SideContentTab[] = [
6566
{
6667
label: `Task ${this.props.questionId}`,
6768
icon: IconNames.NINJA,
@@ -88,10 +89,17 @@ class Assessment extends React.Component<AssessmentProps, { showOverlay: boolean
8889
hasSaveButton: true,
8990
hasShareButton: false
9091
}
92+
const workspaceProps: WorkspaceProps = {
93+
controlBarOptions,
94+
sideContentTabs,
95+
editorValue: (this.props.assessment.questions[this.props.questionId] as IProgrammingQuestion)
96+
.solutionTemplate,
97+
mcq: this.props.assessment.questions[this.props.questionId] as IMCQQuestion
98+
}
9199
return (
92100
<div className="Assessment pt-dark">
93101
{overlay}
94-
<Workspace controlBarOptions={controlBarOptions} sideContentTabs={tabs} />
102+
<Workspace {...workspaceProps} />
95103
</div>
96104
)
97105
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Button, Card, Text, Tooltip } from '@blueprintjs/core'
2+
import * as React from 'react'
3+
4+
import { IMCQQuestion } from '../assessment/assessmentShape'
5+
6+
export interface IMCQChooserProps {
7+
mcq: IMCQQuestion
8+
mcqSubmit?: (choiceId: number) => void
9+
}
10+
11+
class MCQChooser extends React.Component<IMCQChooserProps, {}> {
12+
public render() {
13+
const mockMcqSubmit = (i: number) => () => {}
14+
const options = this.props.mcq.choices.map((choice, i) => (
15+
<Button className="mcq-option col-xs-6" onClick={mockMcqSubmit(i)}>
16+
<Tooltip key={i} content={choice.hint}>
17+
<Text className="Text"> {choice.content} </Text>
18+
</Tooltip>
19+
</Button>
20+
))
21+
return (
22+
<div className="MCQChooser">
23+
<Card className="mcq-content-parent row center-xs">
24+
<div className="col-xs-12">
25+
<div className="mcq-task-parent row center-xs ">
26+
<Card className="mcq-task col-xs-12" elevation={2}>
27+
<Text className="Text"> {this.props.mcq.content} </Text>
28+
</Card>
29+
</div>
30+
<div className="row mcq-options-parent center-xs">{options}</div>
31+
</div>
32+
</Card>
33+
</div>
34+
)
35+
}
36+
}
37+
38+
export default MCQChooser

src/components/workspace/index.tsx

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import * as React from 'react'
44

55
import ControlBarContainer from '../../containers/workspace/ControlBarContainer'
66
import EditorContainer from '../../containers/workspace/EditorContainer'
7+
import MCQChooserContainer from '../../containers/workspace/MCQChooserContainer'
78
import ReplContainer from '../../containers/workspace/ReplContainer'
89
import SideContent from '../../containers/workspace/SideContentContainer'
10+
import { IMCQQuestion } from '../assessment/assessmentShape'
911
import { OwnProps as ControlBarOwnProps } from './ControlBar'
1012
import { SideContentTab } from './side-content'
1113

@@ -21,8 +23,10 @@ export type DispatchProps = {
2123
export type OwnProps = {
2224
controlBarOptions?: ControlBarOwnProps
2325
libQuery?: number
24-
sideContentTabs: SideContentTab[]
2526
prgrmQuery?: string
27+
editorValue?: string
28+
mcq?: IMCQQuestion
29+
sideContentTabs: SideContentTab[]
2630
}
2731

2832
export type StateProps = {
@@ -63,9 +67,7 @@ class Workspace extends React.Component<WorkspaceProps, {}> {
6367
<ControlBarContainer {...this.props.controlBarOptions} />
6468
<div className="row workspace-parent">
6569
<div className="editor-divider" ref={e => (this.editorDividerDiv = e!)} />
66-
<Resizable {...this.editorResizableProps()}>
67-
<EditorContainer />
68-
</Resizable>
70+
<Resizable {...this.editorResizableProps()}>{this.workspaceInput(this.props)}</Resizable>
6971
<div className="right-parent">
7072
<Resizable {...this.sideContentResizableProps()}>
7173
<SideContent {...{ tabs: this.props.sideContentTabs }} />
@@ -151,6 +153,14 @@ class Workspace extends React.Component<WorkspaceProps, {}> {
151153
this.sideDividerDiv.style.display = 'initial'
152154
}
153155
}
156+
157+
private workspaceInput = (props: WorkspaceProps) => {
158+
if (props.editorValue !== undefined) {
159+
return <EditorContainer editorValue={props.editorValue} />
160+
} else {
161+
return <MCQChooserContainer mcq={this.props.mcq!} />
162+
}
163+
}
154164
}
155165

156166
const rightResizeOnly = {
Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1+
import { connect, MapStateToProps } from 'react-redux'
12
import { withRouter } from 'react-router'
2-
import Playground from '../components/Playground'
33

4-
export default withRouter(Playground)
4+
import Playground, { IPlaygroundProps } from '../components/Playground'
5+
import { IState } from '../reducers/states'
6+
7+
type StateProps = Pick<IPlaygroundProps, 'editorValue'>
8+
9+
const mapStateToProps: MapStateToProps<StateProps, {}, IState> = state => ({
10+
editorValue: state.playground.editorValue
11+
})
12+
13+
export default withRouter(connect(mapStateToProps)(Playground))

src/containers/workspace/EditorContainer.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,10 @@ import { evalEditor, updateEditorValue } from '../../actions/playground'
55
import Editor, { IEditorProps } from '../../components/workspace/Editor'
66
import { IState } from '../../reducers/states'
77

8-
type StateProps = Pick<IEditorProps, 'editorValue'>
98
type DispatchProps = Pick<IEditorProps, 'handleEditorValueChange'> &
109
Pick<IEditorProps, 'handleEditorEval'>
1110

12-
const mapStateToProps: MapStateToProps<StateProps, {}, IState> = state => {
13-
return {
14-
editorValue: state.playground.editorValue
15-
}
16-
}
11+
const mapStateToProps: MapStateToProps<{}, {}, IState> = state => ({})
1712

1813
const mapDispatchToProps: MapDispatchToProps<DispatchProps, {}> = (dispatch: Dispatch<any>) =>
1914
bindActionCreators(

0 commit comments

Comments
 (0)