Restructure signup questions widget

This commit is contained in:
Jan Tuomi
2019-03-13 17:38:47 +02:00
parent c2163a858b
commit c0168c6a14
6 changed files with 130 additions and 75 deletions
@@ -0,0 +1,46 @@
import * as React from "react";
import * as shortid from "shortid";
import { Question, InputProps, optionTypes, SignupQuestionError } from "./index";
export interface OptionsWidgetProps {
inputProps: InputProps;
onChange: (value: Question[]) => void;
}
export interface OptionsWidgetState { }
class OptionsWidget extends React.Component<OptionsWidgetProps, OptionsWidgetState> {
handleRadiobuttonOptionsChange = (questions: Question[], index: number) => (event) => {
const { onChange } = this.props;
const val = event.target.value;
const lst = val.split(",").map(p => p.trimLeft());
questions[index].options = lst;
onChange(questions);
}
render() {
const { inputProps } = this.props;
const { type, value, questions, index } = inputProps;
if (!optionTypes.includes(type)) {
throw new SignupQuestionError(`Qquestion widget type "${type}" not in types array.`);
}
if (type === "text") {
return null;
}
else if (type === "radiobutton") {
const lst = value as string[];
const joinedValue = lst.join(",");
return <input
type="text"
placeholder="Yes,no,maybe"
value={joinedValue}
onChange={this.handleRadiobuttonOptionsChange(questions, index)} />;
}
throw new SignupQuestionError(`Unrecognized question widget type "${type}"`);
}
}
export default OptionsWidget;
@@ -0,0 +1,15 @@
@import "../../assets/scss/globals";
.signup-questions-widget {
button.add-link {
background: none;
padding: 0;
margin: 1rem 0;
}
.signup-questions-widget-row {
margin-bottom: 1rem;
display: flex;
flex-flow: column nowrap;
}
}
@@ -1,5 +1,11 @@
import * as React from "react";
import * as shortid from "shortid";
import OptionsWidget from "./OptionsWidget";
import { Question, InputProps, optionTypes } from ".";
// @ts-ignore
import * as AddIcon from "../../assets/img/add-icon.png";
import "./SignupQuestionsWidget.scss";
import TypeWidget from "./TypeWidget";
export interface SignupQuestionsWidgetProps {
value: string;
@@ -9,27 +15,6 @@ export interface SignupQuestionsWidgetProps {
}
export interface SignupQuestionsWidgetState {}
interface Question {
id: string;
name: string;
type: string;
options: string[];
}
interface InputProps {
index: number;
value: string | string[];
questions: Question[];
type: string;
}
const types = [
"text",
"radiobutton",
];
class SignupQuestionError extends Error {}
class SignupQuestionsWidget extends React.Component<SignupQuestionsWidgetProps, SignupQuestionsWidgetState> {
onValueChange = (questions: Question[]) => {
const { onChange } = this.props;
@@ -55,67 +40,18 @@ class SignupQuestionsWidget extends React.Component<SignupQuestionsWidgetProps,
this.onValueChange(questions);
}
handleTypeChange = (questions: Question[], index: number) => (event) => {
const val = event.target.value;
questions[index].type = val;
this.onValueChange(questions);
}
handleRadiobuttonOptionsChange = (questions: Question[], index: number) => (event) => {
const val = event.target.value;
const lst = val.split(",").map(p => p.trimLeft());
questions[index].options = lst;
this.onValueChange(questions);
}
renderTextWidget = ({ questions, value, index }: InputProps) => (
<input type="text" value={value} onChange={this.handleNameInputChange(questions, index)} />
)
renderOptionsWidgetByType = (props: InputProps) => {
const { type, value, questions, index } = props;
if (!types.includes(type)) {
throw new SignupQuestionError(`Qquestion widget type "${type}" not in types array.`);
}
if (type === "text") {
return null;
}
else if (type === "radiobutton") {
const lst = value as string[];
const joinedValue = lst.join(",");
return <input
type="text"
placeholder="Yes,no,maybe"
value={joinedValue}
onChange={this.handleRadiobuttonOptionsChange(questions, index)} />;
}
throw new SignupQuestionError(`Unrecognized question widget type "${type}"`);
}
renderTypeSelectWidget = (props: InputProps) => {
const { questions, index, type } = props;
const options = types.map(t => (
<option key={t} value={t}>{t}</option>
));
return (
<select onChange={this.handleTypeChange(questions, index)} value={type} name="type">
{ options }
</select>
);
}
renderQuestions = (questions: Question[]) => {
return questions.map((q, index) => {
const nameWidgetProps = { value: q.name, type: "text", questions, index };
const nameWidget = this.renderTextWidget(nameWidgetProps);
const optionsWidgetProps = { value: q.options, type: q.type, questions, index };
const optionsWidget = this.renderOptionsWidgetByType(optionsWidgetProps);
const typeSelectWidget = this.renderTypeSelectWidget(optionsWidgetProps);
const dataProps = { value: q.options, type: q.type, questions, index };
const optionsWidget = <OptionsWidget inputProps={dataProps} onChange={this.onValueChange} />;
const typeSelectWidget = <TypeWidget inputProps={dataProps} onChange={this.onValueChange} />;
return (
<div key={q.id} className="signup-questions-widget-row">
{ nameWidget }
@@ -133,8 +69,10 @@ class SignupQuestionsWidget extends React.Component<SignupQuestionsWidgetProps,
return (
<div className="signup-questions-widget">
<button type="button" onClick={this.handleNewRowClick(questions)}>New Row</button>
{this.renderQuestions(questions)}
<button type="button" className="add-link" onClick={this.handleNewRowClick(questions)}>
<img src={AddIcon} /> New Question
</button>
</div>
);
}
@@ -0,0 +1,33 @@
import * as React from "react";
import * as shortid from "shortid";
import { Question, InputProps, optionTypes, SignupQuestionError } from "./index";
export interface TypeWidgetProps {
inputProps: InputProps;
onChange: (value: Question[]) => void;
}
export interface TypeWidgetState { }
class TypeWidget extends React.Component<TypeWidgetProps, TypeWidgetState> {
handleTypeChange = (questions: Question[], index: number) => (event) => {
const { onChange } = this.props;
const val = event.target.value;
questions[index].type = val;
onChange(questions);
}
render() {
const { inputProps } = this.props;
const { type, questions, index } = inputProps;
const options = optionTypes.map(t => (
<option key={t} value={t}>{t}</option>
));
return (
<select onChange={this.handleTypeChange(questions, index)} value={type} name="type">
{options}
</select>
);
}
}
export default TypeWidget;
@@ -1,2 +1,24 @@
import SignupQuestionsWidget from "./SignupQuestionsWidget";
export interface Question {
id: string;
name: string;
type: string;
options: string[];
}
export interface InputProps {
index: number;
value: string | string[];
questions: Question[];
type: string;
}
export const optionTypes = [
"text",
"radiobutton",
];
export class SignupQuestionError extends Error { }
export default SignupQuestionsWidget;
@@ -20,7 +20,8 @@
margin-bottom: 0.5rem;
}
input {
input,
select {
padding: 0.3rem 0.5rem;
margin-bottom: 0.5rem;
}