aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/InputTypes/Checkbox.tsx22
-rw-r--r--src/components/InputTypes/Code.tsx11
-rw-r--r--src/components/InputTypes/Radio.tsx18
-rw-r--r--src/components/InputTypes/Range.tsx52
-rw-r--r--src/components/InputTypes/Select.tsx60
-rw-r--r--src/components/InputTypes/ShortText.tsx11
-rw-r--r--src/components/InputTypes/TextArea.tsx11
-rw-r--r--src/components/InputTypes/index.tsx71
8 files changed, 256 insertions, 0 deletions
diff --git a/src/components/InputTypes/Checkbox.tsx b/src/components/InputTypes/Checkbox.tsx
new file mode 100644
index 0000000..ed02b83
--- /dev/null
+++ b/src/components/InputTypes/Checkbox.tsx
@@ -0,0 +1,22 @@
+/** @jsx jsx */
+import { jsx } from "@emotion/react";
+import React, { ChangeEvent } from "react";
+
+interface CheckboxProps {
+ index: number,
+ option: string,
+ handler: (event: ChangeEvent<HTMLInputElement>) => void
+}
+
+export default function Checkbox(props: CheckboxProps): JSX.Element {
+ return (
+ <label>
+ <label className="unselected_checkbox_label checkbox_label unselectable">
+ <input type="checkbox" value={props.option}
+ name={`${("000" + props.index).slice(-4)}. ${props.option}`} onChange={props.handler}/>
+ <span className="checkmark_span"/>
+ </label>
+ {props.option}<br/>
+ </label>
+ );
+}
diff --git a/src/components/InputTypes/Code.tsx b/src/components/InputTypes/Code.tsx
new file mode 100644
index 0000000..51ca98d
--- /dev/null
+++ b/src/components/InputTypes/Code.tsx
@@ -0,0 +1,11 @@
+/** @jsx jsx */
+import { jsx } from "@emotion/react";
+import React, { ChangeEvent } from "react";
+
+interface CodeProps {
+ handler: (event: ChangeEvent<HTMLInputElement>) => void
+}
+
+export default function Code(props: CodeProps): JSX.Element {
+ return <input type="text" className="text" onChange={props.handler}/>;
+}
diff --git a/src/components/InputTypes/Radio.tsx b/src/components/InputTypes/Radio.tsx
new file mode 100644
index 0000000..81f8375
--- /dev/null
+++ b/src/components/InputTypes/Radio.tsx
@@ -0,0 +1,18 @@
+/** @jsx jsx */
+import { jsx } from "@emotion/react";
+import React, { ChangeEvent } from "react";
+
+interface RadioProps {
+ option: string,
+ question_id: string,
+ handler: (event: ChangeEvent<HTMLInputElement>) => void
+}
+
+export default function Radio(props: RadioProps): JSX.Element {
+ return (
+ <label>
+ <input type="radio" name={props.question_id} className="radio" onChange={props.handler}/>
+ {props.option}<br/>
+ </label>
+ );
+}
diff --git a/src/components/InputTypes/Range.tsx b/src/components/InputTypes/Range.tsx
new file mode 100644
index 0000000..a0260ad
--- /dev/null
+++ b/src/components/InputTypes/Range.tsx
@@ -0,0 +1,52 @@
+/** @jsx jsx */
+import { jsx } from "@emotion/react";
+import React from "react";
+
+interface RangeProps {
+ question_id: string,
+ options: Array<string>,
+ state_dict: Map<string, string | boolean | null>
+}
+
+let last_selection: Element;
+
+interface handler_props {
+ state_dict: Map<string, string | boolean | null>,
+ ref: React.RefObject<HTMLLabelElement>
+}
+
+function handler(this: handler_props): void {
+ if (last_selection) {
+ last_selection.classList.toggle("selected");
+ }
+
+ const dot: Element = this.ref.current!.lastElementChild!; // eslint-disable-line
+ dot.classList.toggle("selected");
+
+ last_selection = dot;
+
+ const value: string = this.ref.current!.textContent!; //eslint-disable-line
+ this.state_dict.set("value", value);
+}
+
+export default function Range(props: RangeProps): JSX.Element {
+ const range = props.options.map((option, index) => {
+ const ref: React.RefObject<HTMLLabelElement> = React.createRef();
+ return (
+ <label key={index} ref={ref} onClick={handler.bind({state_dict: props.state_dict, ref: ref})}>
+ <span>{option}</span>
+ <div className="range_dot"/>
+ </label>
+ );
+ });
+
+ return (
+ <div className="range">
+ { range }
+
+ <div className="range_slider_container">
+ <div className="range_slider"/>
+ </div>
+ </div>
+ );
+}
diff --git a/src/components/InputTypes/Select.tsx b/src/components/InputTypes/Select.tsx
new file mode 100644
index 0000000..355f5d0
--- /dev/null
+++ b/src/components/InputTypes/Select.tsx
@@ -0,0 +1,60 @@
+/** @jsx jsx */
+import { jsx } from "@emotion/react";
+import React from "react";
+
+interface SelectProps {
+ options: Array<string>,
+ state_dict: Map<string, string | boolean | null>
+}
+
+interface HandlerProps {
+ props: SelectProps,
+ ref: React.RefObject<HTMLDivElement>
+}
+
+class Select extends React.Component<SelectProps> {
+ constructor(props: SelectProps) {
+ super(props);
+ }
+
+ click_handler(this: HandlerProps, event: React.MouseEvent<HTMLDivElement, MouseEvent>): void {
+ if (!this.ref.current) {
+ return;
+ }
+
+ this.ref.current.classList.toggle("active");
+
+ const target: Element = (event.target as Element);
+ if (target.id === "option") {
+ const selected_option: Element = this.ref.current.getElementsByClassName("selected_option")[0];
+ const new_option_text: string = target.textContent ?? "...";
+
+ if (selected_option.textContent === "..." && target.parentElement) {
+ target.parentElement.remove();
+ } else {
+ target.textContent = selected_option.textContent;
+ }
+
+ selected_option.textContent = new_option_text;
+ this.props.state_dict.set("value", selected_option.textContent);
+ }
+ }
+
+ render(): JSX.Element {
+ const container_ref: React.RefObject<HTMLDivElement> = React.createRef();
+
+ return (
+ <div className="select_container" ref={container_ref} onClick={this.click_handler.bind({ref: container_ref, props: this.props})}>
+ <span className="select_arrow"/>
+ <span className="selected_option">...</span>
+ <div className="select_options_container">
+ <div className="select_options">
+ { this.props.options.map((option, index) => <div key={index}><hr/><div id="option">{option}</div></div>) }
+ </div>
+ </div>
+ </div>
+ );
+ }
+}
+
+export default Select; \ No newline at end of file
diff --git a/src/components/InputTypes/ShortText.tsx b/src/components/InputTypes/ShortText.tsx
new file mode 100644
index 0000000..182571a
--- /dev/null
+++ b/src/components/InputTypes/ShortText.tsx
@@ -0,0 +1,11 @@
+/** @jsx jsx */
+import { jsx } from "@emotion/react";
+import React, { ChangeEvent } from "react";
+
+interface ShortTextProps {
+ handler: (event: ChangeEvent<HTMLInputElement>) => void
+}
+
+export default function ShortText(props: ShortTextProps): JSX.Element {
+ return <input type="text" className="short_text" placeholder="Enter Text..." onChange={props.handler}/>;
+}
diff --git a/src/components/InputTypes/TextArea.tsx b/src/components/InputTypes/TextArea.tsx
new file mode 100644
index 0000000..550adea
--- /dev/null
+++ b/src/components/InputTypes/TextArea.tsx
@@ -0,0 +1,11 @@
+/** @jsx jsx */
+import { jsx } from "@emotion/react";
+import React, { ChangeEvent } from "react";
+
+interface TextAreaProps {
+ handler: (event: ChangeEvent<HTMLTextAreaElement>) => void
+}
+
+export default function TextArea(props: TextAreaProps): JSX.Element {
+ return <textarea className="text_area" placeholder="Enter Text..." onChange={props.handler}/>;
+}
diff --git a/src/components/InputTypes/index.tsx b/src/components/InputTypes/index.tsx
new file mode 100644
index 0000000..b1d8afe
--- /dev/null
+++ b/src/components/InputTypes/index.tsx
@@ -0,0 +1,71 @@
+import Checkbox from "./Checkbox";
+import Code from "./Code";
+import Radio from "./Radio";
+import Range from "./Range";
+import Select from "./Select";
+import ShortText from "./ShortText";
+import TextArea from "./TextArea";
+
+import React, { ChangeEvent } from "react";
+
+import { QuestionType } from "../../api/question";
+import { QuestionProp } from "../Question";
+
+const _require_options: Array<QuestionType> = [
+ QuestionType.Radio,
+ QuestionType.Checkbox,
+ QuestionType.Select,
+ QuestionType.Range
+];
+
+export default function create_input({ question, public_state }: QuestionProp, handler: (event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void): JSX.Element | JSX.Element[] {
+ let result: JSX.Element | JSX.Element[];
+
+ // eslint-disable-next-line
+ // @ts-ignore
+ let options: string[] = question.data["options"];
+
+ // Catch input types that require options but don't have any
+ if ((options === undefined || typeof options !== "object") && _require_options.includes(question.type)) {
+ // TODO: Implement some sort of warning here
+ options = [];
+ }
+
+ /* eslint-disable react/react-in-jsx-scope */
+ switch (question.type) {
+ case QuestionType.TextArea:
+ result = <TextArea handler={handler}/>;
+ break;
+
+ case QuestionType.Checkbox:
+ result = options.map((option, index) => <Checkbox index={index} option={option} handler={handler} key={index}/>);
+ break;
+
+ case QuestionType.Radio:
+ result = options.map((option, index) => <Radio option={option} question_id={question.id} handler={handler} key={index}/>);
+ break;
+
+ case QuestionType.Select:
+ result = <Select options={options} state_dict={public_state}/>;
+ break;
+
+ case QuestionType.ShortText:
+ result = <ShortText handler={handler}/>;
+ break;
+
+ case QuestionType.Range:
+ result = <Range question_id={question.id} options={options} state_dict={public_state}/>;
+ break;
+
+ case QuestionType.Code:
+ // TODO: Implement
+ result = <Code handler={handler}/>;
+ break;
+
+ default:
+ result = <TextArea handler={handler}/>;
+ }
+ /* eslint-enable react/react-in-jsx-scope */
+
+ return result;
+}