From 0da45505d7b5bc4d9b1e4aa1e9489f8b1f165725 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com> Date: Mon, 4 Jan 2021 04:00:10 +0300 Subject: Adds Question Rendering Adds a question component, and calls it on form page. Adds styling for input types and form page. Lays foundation for validation and submission. Signed-off-by: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com> --- src/components/Question.tsx | 128 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/components/Question.tsx (limited to 'src/components/Question.tsx') diff --git a/src/components/Question.tsx b/src/components/Question.tsx new file mode 100644 index 0000000..1c0fb31 --- /dev/null +++ b/src/components/Question.tsx @@ -0,0 +1,128 @@ +/** @jsx jsx */ +import { jsx } from "@emotion/react"; +import React, { ChangeEvent } from "react"; + +import { Question, QuestionType } from "../api/question"; +import create_input from "./InputTypes"; + +const _skip_normal_state: Array = [ + QuestionType.Radio, + QuestionType.Checkbox, + QuestionType.Select, + QuestionType.Section, + QuestionType.Range +]; + +export type QuestionProp = { + question: Question, + public_state: Map, +} + +class RenderedQuestion extends React.Component { + constructor(props: QuestionProp) { + super(props); + if (props.question.type === QuestionType.TextArea) { + this.handler = this.text_area_handler.bind(this); + } else { + this.handler = this.normal_handler.bind(this); + } + + if (!_skip_normal_state.includes(props.question.type)) { + this._setState("value", ""); + } + } + + _setState(target: string, value: string | boolean | null, callback?:() => void): void { + this.setState({[target]: value}, callback); + this.props.public_state.set(target, value); + } + + handler(_: ChangeEvent): void {} // eslint-disable-line + + normal_handler(event: ChangeEvent): void { + let target: string; + let value: string | boolean; + + switch (event.target.type) { + case QuestionType.Checkbox: + target = this.props.question.id; + value = event.target.checked; + break; + + case QuestionType.Radio: + target = "value"; + if (event.target.parentElement) { + value = event.target.parentElement.innerText.trimEnd(); + } else { + value = event.target.value; + } + break; + + case QuestionType.Select: + // Handled by component + return; + + default: + target = "value"; + value = event.target.value; + } + + this._setState(target, value); + + // Toggle checkbox class + if (event.target.type == "checkbox" && event.target.parentElement !== null) { + event.target.parentElement.classList.toggle("unselected_checkbox_label"); + event.target.parentElement.classList.toggle("selected_checkbox_label"); + } + } + + text_area_handler(event: ChangeEvent): void { + this._setState("value", event.target.value); + } + + componentDidMount(): void { + // Initialize defaults for complex and nested fields + const options: string | string[] = this.props.question.data["options"]; + + if (this.props.public_state.size === 0) { + switch (this.props.question.type) { + case QuestionType.Checkbox: + if (typeof options === "string") { + return; + } + + options.forEach((option, index) => { + this._setState(`${("000" + index).slice(-4)}. ${option}`, false); + }); + break; + + case QuestionType.Range: + case QuestionType.Radio: + case QuestionType.Select: + this._setState("value", null); + break; + } + } + } + + render(): JSX.Element { + const question = this.props.question; + + if (question.type === QuestionType.Section) { + return
+

{question.name}

+ { question.data["text"] ?

{question.data["text"]}

: "" } +
+
; + } else { + return
+

+ {question.name}* +

+ { create_input(this.props, this.handler) }
+
; + } + } +} + +export default RenderedQuestion; -- cgit v1.2.3