diff options
author | 2021-02-23 09:46:27 +0200 | |
---|---|---|
committer | 2021-02-23 09:46:27 +0200 | |
commit | dfbd9eb719bda4a672884bb7d42c353fde75a5e6 (patch) | |
tree | 7d0ba7016a3dc6d41f74052c7db126a2adf37045 | |
parent | Change Redux store items from map to object (diff) |
Use values from Redux in fieldsredux-hcaptcha
-rw-r--r-- | src/components/InputTypes/Checkbox.tsx | 18 | ||||
-rw-r--r-- | src/components/InputTypes/Radio.tsx | 8 | ||||
-rw-r--r-- | src/components/InputTypes/Range.tsx | 8 | ||||
-rw-r--r-- | src/components/InputTypes/Select.tsx | 6 | ||||
-rw-r--r-- | src/components/InputTypes/TextArea.tsx | 12 | ||||
-rw-r--r-- | src/components/InputTypes/index.tsx | 8 | ||||
-rw-r--r-- | src/components/Question.tsx | 43 |
7 files changed, 70 insertions, 33 deletions
diff --git a/src/components/InputTypes/Checkbox.tsx b/src/components/InputTypes/Checkbox.tsx index 38b8ee8..9c633f0 100644 --- a/src/components/InputTypes/Checkbox.tsx +++ b/src/components/InputTypes/Checkbox.tsx @@ -3,13 +3,15 @@ import { jsx, css } from "@emotion/react"; import React, { ChangeEvent } from "react"; import colors from "../../colors"; import { multiSelectInput, hiddenInput } from "../../commonStyles"; -import {useSelector} from "react-redux"; -import {FormState} from "../../store/form/types"; +import { useSelector } from "react-redux"; +import { FormState } from "../../store/form/types"; +import { Question } from "../../api/question"; interface CheckboxProps { index: number, option: string, - handler: (event: ChangeEvent<HTMLInputElement>) => void + handler: (event: ChangeEvent<HTMLInputElement>) => void, + question: Question } const generalStyles = css` @@ -58,10 +60,16 @@ export default function Checkbox(props: CheckboxProps): JSX.Element { const values = useSelector<FormState, FormState["values"]>( state => state.values ); + let value = values[props.question.id]; + if (typeof value !== "object" || !value) { + value = {}; + } + const checked = value[`${("000" + props.index).slice(-4)}. ${props.option}`]; + return ( <label css={[generalStyles, activeStyles]}> - <label className="unselected" css={multiSelectInput}> - <input type="checkbox" value={props.option} css={hiddenInput} name={`${("000" + props.index).slice(-4)}. ${props.option}`} onChange={props.handler} checked={!!values[`${("000" + props.index).slice(-4)}. ${props.option}`]}/> + <label className={checked ? "selected" : "unselected"} css={multiSelectInput}> + <input type="checkbox" value={props.option} css={hiddenInput} name={`${("000" + props.index).slice(-4)}. ${props.option}`} onChange={props.handler} checked={checked}/> <span className="checkmark"/> </label> {props.option}<br/> diff --git a/src/components/InputTypes/Radio.tsx b/src/components/InputTypes/Radio.tsx index a857964..68c9519 100644 --- a/src/components/InputTypes/Radio.tsx +++ b/src/components/InputTypes/Radio.tsx @@ -3,6 +3,8 @@ import { jsx, css } from "@emotion/react"; import React, { ChangeEvent } from "react"; import colors from "../../colors"; import { multiSelectInput, hiddenInput } from "../../commonStyles"; +import { useSelector } from "react-redux"; +import { FormState } from "../../store/form/types"; interface RadioProps { option: string, @@ -30,9 +32,13 @@ const styles = css` `; export default function Radio(props: RadioProps): JSX.Element { + const values = useSelector<FormState, FormState["values"]>( + state => state.values + ); + const value = values[props.question_id]; return ( <label css={styles}> - <input type="radio" name={props.question_id} onChange={props.handler} css={hiddenInput} onBlur={props.onBlurHandler}/> + <input type="radio" name={props.question_id} onChange={props.handler} css={hiddenInput} onBlur={props.onBlurHandler} checked={value === props.option}/> <div css={multiSelectInput}/> {props.option}<br/> </label> diff --git a/src/components/InputTypes/Range.tsx b/src/components/InputTypes/Range.tsx index 23cb3f6..8d37b8a 100644 --- a/src/components/InputTypes/Range.tsx +++ b/src/components/InputTypes/Range.tsx @@ -3,6 +3,8 @@ import { jsx, css } from "@emotion/react"; import React, { ChangeEvent } from "react"; import colors from "../../colors"; import { hiddenInput, multiSelectInput } from "../../commonStyles"; +import { useSelector } from "react-redux"; +import { FormState } from "../../store/form/types"; interface RangeProps { question_id: string, @@ -97,11 +99,15 @@ const sliderStyles = css` `; export default function Range(props: RangeProps): JSX.Element { + const values = useSelector<FormState, FormState["values"]>( + state => state.values + ); + const value = values[props.question_id]; const range = props.options.map((option, index) => { return ( <label css={[selectorStyles, css`width: 1rem`]} key={index}> <span css={optionStyles}>{option}</span> - <input type="radio" name={props.question_id} css={hiddenInput} onChange={props.handler} onBlur={props.onBlurHandler}/> + <input type="radio" name={props.question_id} css={hiddenInput} onChange={props.handler} onBlur={props.onBlurHandler} checked={value === option}/> <div css={multiSelectInput}/> </label> ); diff --git a/src/components/InputTypes/Select.tsx b/src/components/InputTypes/Select.tsx index c0f5425..82e0975 100644 --- a/src/components/InputTypes/Select.tsx +++ b/src/components/InputTypes/Select.tsx @@ -16,11 +16,11 @@ interface SelectProps { } interface SelectStateProps { - values: Map<string, string | Map<string, boolean> | null> + values: { [key: string]: string | { [subKey: string]: boolean; } | null; } } interface SelectDispatchProps { - setValue: (question: Question, value: string | Map<string, boolean> | null) => SetValueAction + setValue: (question: Question, value: string | { [key: string]: boolean } | null) => SetValueAction } const containerStyles = css` @@ -191,7 +191,7 @@ class Select extends React.Component<SelectProps & SelectStateProps & SelectDisp } focusOption(): void { - if (!this.props.values.get(this.props.question.id)) { + if (!(this.props.question.id in this.props.values) || !this.props.values[this.props.question.id]) { this.props.setValue(this.props.question, "temporary"); this.props.onBlurHandler(); this.props.setValue(this.props.question, null); diff --git a/src/components/InputTypes/TextArea.tsx b/src/components/InputTypes/TextArea.tsx index 08424fb..a32094c 100644 --- a/src/components/InputTypes/TextArea.tsx +++ b/src/components/InputTypes/TextArea.tsx @@ -2,13 +2,17 @@ import { jsx, css } from "@emotion/react"; import React, { ChangeEvent } from "react"; import { invalidStyles, textInputs } from "../../commonStyles"; +import { useSelector } from "react-redux"; +import { FormState } from "../../store/form/types"; +import { Question } from "../../api/question"; interface TextAreaProps { handler: (event: ChangeEvent<HTMLTextAreaElement>) => void, onBlurHandler: () => void, valid: boolean, // eslint-disable-next-line @typescript-eslint/no-explicit-any - focus_ref: React.RefObject<any> + focus_ref: React.RefObject<any>, + question: Question } const styles = css` @@ -21,9 +25,13 @@ const styles = css` `; export default function TextArea(props: TextAreaProps): JSX.Element { + const values = useSelector<FormState, FormState["values"]>( + state => state.values + ); + const value = values[props.question.id]; return ( <div css={invalidStyles}> - <textarea css={[textInputs, styles]} placeholder="Enter Text..." onChange={props.handler} onBlur={props.onBlurHandler} className={!props.valid ? "invalid-box" : ""} ref={props.focus_ref}/> + <textarea css={[textInputs, styles]} value={typeof value === "string" ? value : ""} placeholder="Enter Text..." onChange={props.handler} onBlur={props.onBlurHandler} className={!props.valid ? "invalid-box" : ""} ref={props.focus_ref}/> </div> ); } diff --git a/src/components/InputTypes/index.tsx b/src/components/InputTypes/index.tsx index ff02259..97fd790 100644 --- a/src/components/InputTypes/index.tsx +++ b/src/components/InputTypes/index.tsx @@ -37,11 +37,11 @@ export default function create_input(props: QuestionProp & QuestionStateProp & Q /* eslint-disable react/react-in-jsx-scope */ switch (question.type) { case QuestionType.TextArea: - result = <TextArea handler={handler} valid={valid} onBlurHandler={onBlurHandler} focus_ref={focus_ref}/>; + result = <TextArea question={question} handler={handler} valid={valid} onBlurHandler={onBlurHandler} focus_ref={focus_ref}/>; break; case QuestionType.Checkbox: - result = options.map((option, index) => <Checkbox index={index} option={option} handler={handler} key={index}/>); + result = options.map((option, index) => <Checkbox question={question} index={index} option={option} handler={handler} key={index}/>); break; case QuestionType.Radio: @@ -53,7 +53,7 @@ export default function create_input(props: QuestionProp & QuestionStateProp & Q break; case QuestionType.ShortText: - result = <ShortText handler={handler} onBlurHandler={onBlurHandler} valid={valid} focus_ref={focus_ref} question={question}/>; + result = <ShortText key={props.question.id} handler={handler} onBlurHandler={onBlurHandler} valid={valid} focus_ref={focus_ref} question={question}/>; break; case QuestionType.Range: @@ -66,7 +66,7 @@ export default function create_input(props: QuestionProp & QuestionStateProp & Q break; default: - result = <TextArea handler={handler} valid={valid} onBlurHandler={onBlurHandler} focus_ref={focus_ref}/>; + result = <TextArea question={question} handler={handler} valid={valid} onBlurHandler={onBlurHandler} focus_ref={focus_ref}/>; } /* eslint-enable react/react-in-jsx-scope */ diff --git a/src/components/Question.tsx b/src/components/Question.tsx index 7212a2d..74ee86f 100644 --- a/src/components/Question.tsx +++ b/src/components/Question.tsx @@ -1,14 +1,14 @@ /** @jsx jsx */ import { jsx, css } from "@emotion/react"; -import React, { ChangeEvent } from "react"; -import { connect } from "react-redux"; +import React, {ChangeEvent} from "react"; +import {connect} from "react-redux"; -import { Question, QuestionType } from "../api/question"; -import { selectable } from "../commonStyles"; +import {Question, QuestionType} from "../api/question"; +import {selectable} from "../commonStyles"; import create_input from "./InputTypes"; import ErrorMessage from "./ErrorMessage"; -import { FormState } from "../store/form/types"; -import { setError, SetErrorAction, setValid, SetValidAction, setValue, SetValueAction } from "../store/form/actions"; +import {FormState} from "../store/form/types"; +import {setError, SetErrorAction, setValid, SetValidAction, setValue, SetValueAction} from "../store/form/actions"; const skip_normal_state: Array<QuestionType> = [ QuestionType.Radio, @@ -47,10 +47,14 @@ export class RenderedQuestion extends React.Component<QuestionProp & QuestionSta } this.blurHandler = this.blurHandler.bind(this); - props.setValid(props.question, true); - props.setError(props.question, ""); + if (!(props.question.id in props.valid)) { + props.setValid(props.question, true); + } + if (!(props.question.id in props.errors)) { + props.setError(props.question, ""); + } - if (!skip_normal_state.includes(props.question.type)) { + if (!skip_normal_state.includes(props.question.type) && !(props.question.id in props.values)) { props.setValue(props.question, ""); } } @@ -102,12 +106,6 @@ export class RenderedQuestion extends React.Component<QuestionProp & QuestionSta this.props.setValue(this.props.question, value); } - // Toggle checkbox class - if (event.target.type == "checkbox" && event.target.parentElement !== null) { - event.target.parentElement.classList.toggle("unselected"); - event.target.parentElement.classList.toggle("selected"); - } - const options: string | string[] = this.props.question.data["options"]; switch (event.target.type) { case "text": @@ -194,17 +192,28 @@ export class RenderedQuestion extends React.Component<QuestionProp & QuestionSta } componentDidMount(): void { + // We don't want to set if we already have them in values. + if (this.props.question.id in this.props.values) { + return; + } + // Initialize defaults for complex and nested fields const options: string | string[] = this.props.question.data["options"]; - const values = this.props.values[this.props.question.id]; + let values = this.props.values[this.props.question.id]; switch (this.props.question.type) { case QuestionType.Checkbox: - if (typeof options === "string" || !(typeof values === "object") || !values) { + if (typeof options === "string") { return; } + if (!(typeof values === "object") || !values) { + values = {}; + } + options.forEach((option, index) => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore values[`${("000" + index).slice(-4)}. ${option}`] = false; }); this.props.setValue(this.props.question, values); |