Restructure signup questions widget
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user