Skip to content

Commit

Permalink
Add MCQ option display for MCQ Questions (#128)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
remo5000 authored and ning-y committed Jun 23, 2018
1 parent 9184621 commit 6e93ec9
Show file tree
Hide file tree
Showing 12 changed files with 124 additions and 24 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"private": true,
"name": "cadet-frontend",
"version": "0.1.0",
"version": "0.1.1",
"scripts-info": {
"format": "Format source code",
"start": "Start the Webpack development server",
Expand Down
13 changes: 8 additions & 5 deletions src/components/Playground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,20 @@ import WorkspaceContainer from '../containers/workspace'
import { sourceChapters } from '../reducers/states'
import { SideContentTab } from './workspace/side-content'

export type PlaygroundProps = RouteComponentProps<{}>
export interface IPlaygroundProps extends RouteComponentProps<{}> {
editorValue: string
}

type PlaygroundState = {
isGreen: boolean
}

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

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

constructor(props: PlaygroundProps) {
constructor(props: IPlaygroundProps) {
super(props)
this.state = { isGreen: false }
this.handlers.goGreen = this.toggleIsGreen.bind(this)
Expand All @@ -36,6 +38,7 @@ class Playground extends React.Component<PlaygroundProps, PlaygroundState> {
<WorkspaceContainer
libQuery={parseLibrary(this.props)}
prgrmQuery={parsePrgrm(this.props)}
editorValue={this.props.editorValue}
sideContentTabs={[playgroundIntroduction]}
/>
</HotKeys>
Expand All @@ -47,13 +50,13 @@ class Playground extends React.Component<PlaygroundProps, PlaygroundState> {
}
}

const parsePrgrm = (props: PlaygroundProps) => {
const parsePrgrm = (props: IPlaygroundProps) => {
const qsParsed = qs.parse(props.location.hash)
// legacy support
return qsParsed.lz !== undefined ? qsParsed.lz : qsParsed.prgrm
}

const parseLibrary = (props: PlaygroundProps) => {
const parseLibrary = (props: IPlaygroundProps) => {
const libQuery = qs.parse(props.location.hash).lib
const lib = libQuery === undefined ? NaN : parseInt(libQuery, 10)
return sourceChapters.includes(lib) ? lib : undefined
Expand Down
3 changes: 2 additions & 1 deletion src/components/__tests__/Playground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import Playground from '../Playground'

test('Playground renders correctly', () => {
const props = {
...mockRouterProps('/academy', {})
...mockRouterProps('/academy', {}),
editorValue: 'Test value'
}
const app = <Playground {...props} />
const tree = shallow(app)
Expand Down
2 changes: 1 addition & 1 deletion src/components/__tests__/__snapshots__/Playground.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

exports[`Playground renders correctly 1`] = `
"<HotKeys className=\\"Playground pt-dark\\" keyMap={{...}} handlers={{...}}>
<Connect(Workspace) libQuery={[undefined]} prgrmQuery={[undefined]} sideContentTabs={{...}} />
<Connect(Workspace) libQuery={[undefined]} prgrmQuery={[undefined]} editorValue=\\"Test value\\" sideContentTabs={{...}} />
</HotKeys>"
`;
2 changes: 1 addition & 1 deletion src/components/assessment/assessmentShape.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export interface IProgrammingQuestion extends IQuestion {
}

export interface IMCQQuestion extends IQuestion {
choices?: MCQChoice[]
choices: MCQChoice[]
type: 'mcq'
}

Expand Down
14 changes: 11 additions & 3 deletions src/components/assessment/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import * as React from 'react'
import Workspace from '../../containers/workspace'
import { history } from '../../utils/history'
import { assessmentCategoryLink } from '../../utils/paramParseHelpers'
import { OwnProps as WorkspaceProps } from '../workspace'
import { OwnProps as ControlBarOwnProps } from '../workspace/ControlBar'
import { SideContentTab } from '../workspace/side-content'
import { IAssessment } from './assessmentShape'
import { IAssessment, IMCQQuestion, IProgrammingQuestion } from './assessmentShape'

export type AssessmentProps = DispatchProps & OwnProps & StateProps

Expand Down Expand Up @@ -61,7 +62,7 @@ class Assessment extends React.Component<AssessmentProps, { showOverlay: boolean
const shortSummaryElement = (
<Text> {this.props.assessment.questions[this.props.questionId].content} </Text>
)
const tabs: SideContentTab[] = [
const sideContentTabs: SideContentTab[] = [
{
label: `Task ${this.props.questionId}`,
icon: IconNames.NINJA,
Expand All @@ -88,10 +89,17 @@ class Assessment extends React.Component<AssessmentProps, { showOverlay: boolean
hasSaveButton: true,
hasShareButton: false
}
const workspaceProps: WorkspaceProps = {
controlBarOptions,
sideContentTabs,
editorValue: (this.props.assessment.questions[this.props.questionId] as IProgrammingQuestion)
.solutionTemplate,
mcq: this.props.assessment.questions[this.props.questionId] as IMCQQuestion
}
return (
<div className="Assessment pt-dark">
{overlay}
<Workspace controlBarOptions={controlBarOptions} sideContentTabs={tabs} />
<Workspace {...workspaceProps} />
</div>
)
}
Expand Down
38 changes: 38 additions & 0 deletions src/components/workspace/MCQChooser.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Button, Card, Text, Tooltip } from '@blueprintjs/core'
import * as React from 'react'

import { IMCQQuestion } from '../assessment/assessmentShape'

export interface IMCQChooserProps {
mcq: IMCQQuestion
mcqSubmit?: (choiceId: number) => void
}

class MCQChooser extends React.Component<IMCQChooserProps, {}> {
public render() {
const mockMcqSubmit = (i: number) => () => {}
const options = this.props.mcq.choices.map((choice, i) => (
<Button className="mcq-option col-xs-6" onClick={mockMcqSubmit(i)}>
<Tooltip key={i} content={choice.hint}>
<Text className="Text"> {choice.content} </Text>
</Tooltip>
</Button>
))
return (
<div className="MCQChooser">
<Card className="mcq-content-parent row center-xs">
<div className="col-xs-12">
<div className="mcq-task-parent row center-xs ">
<Card className="mcq-task col-xs-12" elevation={2}>
<Text className="Text"> {this.props.mcq.content} </Text>
</Card>
</div>
<div className="row mcq-options-parent center-xs">{options}</div>
</div>
</Card>
</div>
)
}
}

export default MCQChooser
18 changes: 14 additions & 4 deletions src/components/workspace/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import * as React from 'react'

import ControlBarContainer from '../../containers/workspace/ControlBarContainer'
import EditorContainer from '../../containers/workspace/EditorContainer'
import MCQChooserContainer from '../../containers/workspace/MCQChooserContainer'
import ReplContainer from '../../containers/workspace/ReplContainer'
import SideContent from '../../containers/workspace/SideContentContainer'
import { IMCQQuestion } from '../assessment/assessmentShape'
import { OwnProps as ControlBarOwnProps } from './ControlBar'
import { SideContentTab } from './side-content'

Expand All @@ -21,8 +23,10 @@ export type DispatchProps = {
export type OwnProps = {
controlBarOptions?: ControlBarOwnProps
libQuery?: number
sideContentTabs: SideContentTab[]
prgrmQuery?: string
editorValue?: string
mcq?: IMCQQuestion
sideContentTabs: SideContentTab[]
}

export type StateProps = {
Expand Down Expand Up @@ -63,9 +67,7 @@ class Workspace extends React.Component<WorkspaceProps, {}> {
<ControlBarContainer {...this.props.controlBarOptions} />
<div className="row workspace-parent">
<div className="editor-divider" ref={e => (this.editorDividerDiv = e!)} />
<Resizable {...this.editorResizableProps()}>
<EditorContainer />
</Resizable>
<Resizable {...this.editorResizableProps()}>{this.workspaceInput(this.props)}</Resizable>
<div className="right-parent">
<Resizable {...this.sideContentResizableProps()}>
<SideContent {...{ tabs: this.props.sideContentTabs }} />
Expand Down Expand Up @@ -151,6 +153,14 @@ class Workspace extends React.Component<WorkspaceProps, {}> {
this.sideDividerDiv.style.display = 'initial'
}
}

private workspaceInput = (props: WorkspaceProps) => {
if (props.editorValue !== undefined) {
return <EditorContainer editorValue={props.editorValue} />
} else {
return <MCQChooserContainer mcq={this.props.mcq!} />
}
}
}

const rightResizeOnly = {
Expand Down
13 changes: 11 additions & 2 deletions src/containers/PlaygroundContainer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { connect, MapStateToProps } from 'react-redux'
import { withRouter } from 'react-router'
import Playground from '../components/Playground'

export default withRouter(Playground)
import Playground, { IPlaygroundProps } from '../components/Playground'
import { IState } from '../reducers/states'

type StateProps = Pick<IPlaygroundProps, 'editorValue'>

const mapStateToProps: MapStateToProps<StateProps, {}, IState> = state => ({
editorValue: state.playground.editorValue
})

export default withRouter(connect(mapStateToProps)(Playground))
7 changes: 1 addition & 6 deletions src/containers/workspace/EditorContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,10 @@ import { evalEditor, updateEditorValue } from '../../actions/playground'
import Editor, { IEditorProps } from '../../components/workspace/Editor'
import { IState } from '../../reducers/states'

type StateProps = Pick<IEditorProps, 'editorValue'>
type DispatchProps = Pick<IEditorProps, 'handleEditorValueChange'> &
Pick<IEditorProps, 'handleEditorEval'>

const mapStateToProps: MapStateToProps<StateProps, {}, IState> = state => {
return {
editorValue: state.playground.editorValue
}
}
const mapStateToProps: MapStateToProps<{}, {}, IState> = state => ({})

const mapDispatchToProps: MapDispatchToProps<DispatchProps, {}> = (dispatch: Dispatch<any>) =>
bindActionCreators(
Expand Down
3 changes: 3 additions & 0 deletions src/containers/workspace/MCQChooserContainer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import MCQChooser from '../../components/workspace/MCQChooser'

export default MCQChooser
33 changes: 33 additions & 0 deletions src/styles/_workspace.scss
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,37 @@ $code-color-error: #ff4444;
}
}

.MCQChooser {
flex: 1 1;
margin: 0 0.5rem 0 0.5rem;
overflow: hidden;
.mcq-content-parent {
height: 100%;
overflow: auto;
}
.mcq-options-parent {
margin-bottom: 20px;
}
.mcq-option {
// use of !important to override a 'not' selector by BluePrint
background-color: $cadet-color-3 !important;
padding: 20px;
}
.mcq-task-parent {
margin-bottom: 20px;
.pt-card {
background-color: $cadet-color-3;
}
}
.pt-card {
background-color: $cadet-color-2;
}
.Text {
word-break: break-word;
word-wrap: break-word;
}
}

.resize-side-content {
display: flex;
flex-direction: column;
Expand All @@ -91,6 +122,8 @@ $code-color-error: #ff4444;
overflow-y: auto;

.pt-card {
display: flex;
flex-direction: column;
background-color: $cadet-color-2;
color: $code-color-result;
height: 100%;
Expand Down

0 comments on commit 6e93ec9

Please sign in to comment.