aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/Question.tsx
blob: 1c0fb31a5c2cb7bcf748fef2dd9c4918bbca7ecc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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> = [
    QuestionType.Radio,
    QuestionType.Checkbox,
    QuestionType.Select,
    QuestionType.Section,
    QuestionType.Range
];

export type QuestionProp = {
    question: Question,
    public_state: Map<string, string | boolean | null>,
}

class RenderedQuestion extends React.Component<QuestionProp> {
    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<HTMLInputElement | HTMLTextAreaElement>): void {} // eslint-disable-line

    normal_handler(event: ChangeEvent<HTMLInputElement>): 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<HTMLTextAreaElement>): 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 <div>
                <h1 className="selectable">{question.name}</h1>
                { question.data["text"] ? <h3 className="selectable">{question.data["text"]}</h3> : "" }
                <hr className="section_header"/>
            </div>;
        } else {
            return <div>
                <h2 className="selectable">
                    {question.name}<span id={question.required ? "required" : ""} className="required_star">*</span>
                </h2>
                { create_input(this.props, this.handler) }<hr/>
            </div>;
        }
    }
}

export default RenderedQuestion;