diff options
author | 2021-02-20 03:50:58 +0300 | |
---|---|---|
committer | 2021-02-20 03:53:45 +0300 | |
commit | 0278c8f567bfc50fcb65aaf6afe7cd82c5031023 (patch) | |
tree | a20d335623dc8b9e9038de1d5dc03e481039ecd8 /src | |
parent | Removes Path From Auth (diff) | |
parent | Adds Missing Fields To Test Models (diff) |
Merge branch 'main' into discord-oauth
Signed-off-by: Hassan Abouelela <[email protected]>
# Conflicts:
# package.json
# src/commonStyles.tsx
# src/pages/FormPage.tsx
Diffstat (limited to 'src')
-rw-r--r-- | src/api/forms.ts | 3 | ||||
-rw-r--r-- | src/commonStyles.tsx | 12 | ||||
-rw-r--r-- | src/components/ErrorMessage.tsx | 24 | ||||
-rw-r--r-- | src/components/InputTypes/Radio.tsx | 5 | ||||
-rw-r--r-- | src/components/InputTypes/Range.tsx | 6 | ||||
-rw-r--r-- | src/components/InputTypes/Select.tsx | 18 | ||||
-rw-r--r-- | src/components/InputTypes/ShortText.tsx | 14 | ||||
-rw-r--r-- | src/components/InputTypes/TextArea.tsx | 14 | ||||
-rw-r--r-- | src/components/InputTypes/index.tsx | 19 | ||||
-rw-r--r-- | src/components/Question.tsx | 112 | ||||
-rw-r--r-- | src/pages/FormPage.tsx | 127 | ||||
-rw-r--r-- | src/tests/components/FormListing.test.tsx | 6 | ||||
-rw-r--r-- | src/tests/pages/LandingPage.test.tsx | 3 |
13 files changed, 319 insertions, 44 deletions
diff --git a/src/api/forms.ts b/src/api/forms.ts index 12b9abf..77fbb8e 100644 --- a/src/api/forms.ts +++ b/src/api/forms.ts @@ -16,7 +16,8 @@ export interface Form { webhook: WebHook | null, questions: Array<Question>, name: string, - description: string + description: string, + submitted_text: string | null } export interface WebHook { diff --git a/src/commonStyles.tsx b/src/commonStyles.tsx index eb3e319..bfae17e 100644 --- a/src/commonStyles.tsx +++ b/src/commonStyles.tsx @@ -53,6 +53,7 @@ const textInputs = css` const submitStyles = css` text-align: right; + white-space: nowrap; button:disabled { background-color: ${colors.greyple}; @@ -81,6 +82,14 @@ const submitStyles = css` } `; +const invalidStyles = css` + .invalid-box { + -webkit-appearance: none; + -webkit-box-shadow: 0 0 0.6rem ${colors.error}; + box-shadow: 0 0 0.6rem ${colors.error}; + border-color: transparent; + } +`; export { selectable, @@ -88,5 +97,6 @@ export { hiddenInput, multiSelectInput, textInputs, - submitStyles + submitStyles, + invalidStyles }; diff --git a/src/components/ErrorMessage.tsx b/src/components/ErrorMessage.tsx new file mode 100644 index 0000000..650100d --- /dev/null +++ b/src/components/ErrorMessage.tsx @@ -0,0 +1,24 @@ +/** @jsx jsx */ +import { jsx, css } from "@emotion/react"; +import colors from "../colors"; + +interface ErrorMessageProps { + show: boolean, + message: string +} + +export default function ErrorMessage(props: ErrorMessageProps): JSX.Element | null { + const styles = css` + color: ${colors.error}; + font-size: 1.15rem; + line-height: 1.1rem; + margin: 1rem 0 0; + visibility: ${props.show ? "visible" : "hidden"}; + position: absolute; + z-index: -1; + `; + + return ( + <p css={styles}>{props.message}</p> + ); +} diff --git a/src/components/InputTypes/Radio.tsx b/src/components/InputTypes/Radio.tsx index 3bf13ed..a857964 100644 --- a/src/components/InputTypes/Radio.tsx +++ b/src/components/InputTypes/Radio.tsx @@ -7,7 +7,8 @@ import { multiSelectInput, hiddenInput } from "../../commonStyles"; interface RadioProps { option: string, question_id: string, - handler: (event: ChangeEvent<HTMLInputElement>) => void + handler: (event: ChangeEvent<HTMLInputElement>) => void, + onBlurHandler: () => void } const styles = css` @@ -31,7 +32,7 @@ const styles = css` export default function Radio(props: RadioProps): JSX.Element { return ( <label css={styles}> - <input type="radio" name={props.question_id} onChange={props.handler} css={hiddenInput}/> + <input type="radio" name={props.question_id} onChange={props.handler} css={hiddenInput} onBlur={props.onBlurHandler}/> <div css={multiSelectInput}/> {props.option}<br/> </label> diff --git a/src/components/InputTypes/Range.tsx b/src/components/InputTypes/Range.tsx index e2f89f4..23cb3f6 100644 --- a/src/components/InputTypes/Range.tsx +++ b/src/components/InputTypes/Range.tsx @@ -7,7 +7,9 @@ import { hiddenInput, multiSelectInput } from "../../commonStyles"; interface RangeProps { question_id: string, options: Array<string>, - handler: (event: ChangeEvent<HTMLInputElement>) => void + handler: (event: ChangeEvent<HTMLInputElement>) => void, + required: boolean, + onBlurHandler: () => void } const containerStyles = css` @@ -99,7 +101,7 @@ export default function Range(props: RangeProps): JSX.Element { 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}/> + <input type="radio" name={props.question_id} css={hiddenInput} onChange={props.handler} onBlur={props.onBlurHandler}/> <div css={multiSelectInput}/> </label> ); diff --git a/src/components/InputTypes/Select.tsx b/src/components/InputTypes/Select.tsx index e753357..2d0187a 100644 --- a/src/components/InputTypes/Select.tsx +++ b/src/components/InputTypes/Select.tsx @@ -1,11 +1,13 @@ /** @jsx jsx */ import { jsx, css } from "@emotion/react"; import React from "react"; -import { hiddenInput } from "../../commonStyles"; +import { hiddenInput, invalidStyles } from "../../commonStyles"; interface SelectProps { options: Array<string>, - state_dict: Map<string, string | boolean | null> + state_dict: Map<string, string | boolean | null>, + valid: boolean, + onBlurHandler: () => void } const containerStyles = css` @@ -175,6 +177,14 @@ class Select extends React.Component<SelectProps> { } } + focusOption(): void { + if (!this.props.state_dict.get("value")) { + this.props.state_dict.set("value", "temporary"); + this.props.onBlurHandler(); + this.props.state_dict.set("value", null); + } + } + render(): JSX.Element { const container_ref: React.RefObject<HTMLDivElement> = React.createRef(); const selected_option_ref: React.RefObject<HTMLDivElement> = React.createRef(); @@ -182,8 +192,8 @@ class Select extends React.Component<SelectProps> { const handle_click = (event: React.MouseEvent<HTMLDivElement> | React.KeyboardEvent<HTMLDivElement>) => this.handle_click(container_ref, selected_option_ref, event); return ( - <div css={[containerStyles, arrowStyles, optionContainerStyles]} ref={container_ref}> - <div className="selected_container" css={mainWindowStyles}> + <div css={[containerStyles, arrowStyles, optionContainerStyles, invalidStyles]} onFocus={this.focusOption.bind(this)} ref={container_ref} onBlur={this.props.onBlurHandler}> + <div css={mainWindowStyles} className={!this.props.valid ? "invalid-box selected_container" : "selected_container"}> <span className="arrow"/> <div tabIndex={0} className="selected_option" ref={selected_option_ref} onMouseDown={handle_click} onKeyDown={handle_click}>...</div> </div> diff --git a/src/components/InputTypes/ShortText.tsx b/src/components/InputTypes/ShortText.tsx index 1e38bcd..8d99dc6 100644 --- a/src/components/InputTypes/ShortText.tsx +++ b/src/components/InputTypes/ShortText.tsx @@ -1,12 +1,20 @@ /** @jsx jsx */ import { jsx } from "@emotion/react"; import React, { ChangeEvent } from "react"; -import { textInputs } from "../../commonStyles"; +import { textInputs, invalidStyles } from "../../commonStyles"; interface ShortTextProps { - handler: (event: ChangeEvent<HTMLInputElement>) => void + handler: (event: ChangeEvent<HTMLInputElement>) => void, + onBlurHandler: () => void, + valid: boolean, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + focus_ref: React.RefObject<any> } export default function ShortText(props: ShortTextProps): JSX.Element { - return <input type="text" css={textInputs} placeholder="Enter Text..." onChange={props.handler}/>; + return ( + <div css={invalidStyles}> + <input type="text" css={textInputs} 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/TextArea.tsx b/src/components/InputTypes/TextArea.tsx index 6e46c27..08424fb 100644 --- a/src/components/InputTypes/TextArea.tsx +++ b/src/components/InputTypes/TextArea.tsx @@ -1,10 +1,14 @@ /** @jsx jsx */ import { jsx, css } from "@emotion/react"; import React, { ChangeEvent } from "react"; -import { textInputs } from "../../commonStyles"; +import { invalidStyles, textInputs } from "../../commonStyles"; interface TextAreaProps { - handler: (event: ChangeEvent<HTMLTextAreaElement>) => void + handler: (event: ChangeEvent<HTMLTextAreaElement>) => void, + onBlurHandler: () => void, + valid: boolean, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + focus_ref: React.RefObject<any> } const styles = css` @@ -17,5 +21,9 @@ const styles = css` `; export default function TextArea(props: TextAreaProps): JSX.Element { - return <textarea css={[textInputs, styles]} placeholder="Enter Text..." onChange={props.handler}/>; + 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}/> + </div> + ); } diff --git a/src/components/InputTypes/index.tsx b/src/components/InputTypes/index.tsx index f1e0b30..bc65248 100644 --- a/src/components/InputTypes/index.tsx +++ b/src/components/InputTypes/index.tsx @@ -18,12 +18,17 @@ const require_options: Array<QuestionType> = [ QuestionType.Range ]; -export default function create_input({ question, public_state }: QuestionProp, handler: (event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void): JSX.Element | JSX.Element[] { +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export default function create_input({ question, public_state }: QuestionProp, handler: (event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void, onBlurHandler: () => void, focus_ref: React.RefObject<any>): JSX.Element | JSX.Element[] { let result: JSX.Element | JSX.Element[]; // eslint-disable-next-line // @ts-ignore let options: string[] = question.data["options"]; + let valid = true; + if (!public_state.get("valid")) { + valid = false; + } // Catch input types that require options but don't have any if ((options === undefined || typeof options !== "object") && require_options.includes(question.type)) { @@ -34,7 +39,7 @@ export default function create_input({ question, public_state }: QuestionProp, h /* eslint-disable react/react-in-jsx-scope */ switch (question.type) { case QuestionType.TextArea: - result = <TextArea handler={handler}/>; + result = <TextArea handler={handler} valid={valid} onBlurHandler={onBlurHandler} focus_ref={focus_ref}/>; break; case QuestionType.Checkbox: @@ -42,19 +47,19 @@ export default function create_input({ question, public_state }: QuestionProp, h break; case QuestionType.Radio: - result = options.map((option, index) => <Radio option={option} question_id={question.id} handler={handler} key={index}/>); + result = options.map((option, index) => <Radio option={option} question_id={question.id} handler={handler} key={index} onBlurHandler={onBlurHandler}/>); break; case QuestionType.Select: - result = <Select options={options} state_dict={public_state}/>; + result = <Select options={options} state_dict={public_state} valid={valid} onBlurHandler={onBlurHandler}/>; break; case QuestionType.ShortText: - result = <ShortText handler={handler}/>; + result = <ShortText handler={handler} onBlurHandler={onBlurHandler} valid={valid} focus_ref={focus_ref}/>; break; case QuestionType.Range: - result = <Range question_id={question.id} options={options} handler={handler}/>; + result = <Range question_id={question.id} options={options} handler={handler} required={question.required} onBlurHandler={onBlurHandler}/>; break; case QuestionType.Code: @@ -63,7 +68,7 @@ export default function create_input({ question, public_state }: QuestionProp, h break; default: - result = <TextArea handler={handler}/>; + result = <TextArea 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 735d69b..0af745e 100644 --- a/src/components/Question.tsx +++ b/src/components/Question.tsx @@ -5,6 +5,7 @@ import React, { ChangeEvent } from "react"; import { Question, QuestionType } from "../api/question"; import { selectable } from "../commonStyles"; import create_input from "./InputTypes"; +import ErrorMessage from "./ErrorMessage"; const skip_normal_state: Array<QuestionType> = [ QuestionType.Radio, @@ -17,6 +18,9 @@ const skip_normal_state: Array<QuestionType> = [ export type QuestionProp = { question: Question, public_state: Map<string, string | boolean | null>, + scroll_ref: React.RefObject<HTMLDivElement>, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + focus_ref: React.RefObject<any> } class RenderedQuestion extends React.Component<QuestionProp> { @@ -27,6 +31,10 @@ class RenderedQuestion extends React.Component<QuestionProp> { } else { this.handler = this.normal_handler.bind(this); } + this.blurHandler = this.blurHandler.bind(this); + + this.setPublicState("valid", true); + this.setPublicState("error", ""); if (!skip_normal_state.includes(props.question.type)) { this.setPublicState("value", ""); @@ -41,6 +49,18 @@ class RenderedQuestion extends React.Component<QuestionProp> { // This is here to allow dynamic selection between the general handler, and the textarea handler. handler(_: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>): void {} // eslint-disable-line + blurHandler(): void { + if (this.props.question.required) { + if (!this.props.public_state.get("value")) { + this.setPublicState("error", "Field must be filled."); + this.setPublicState("valid", false); + } else { + this.setPublicState("error", ""); + this.setPublicState("valid", true); + } + } + } + normal_handler(event: ChangeEvent<HTMLInputElement>): void { let target: string; let value: string | boolean; @@ -73,12 +93,90 @@ class RenderedQuestion extends React.Component<QuestionProp> { 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": + this.setPublicState("valid", true); + break; + + case "checkbox": + // We need to check this here, because checkbox doesn't have onBlur + if (this.props.question.required && typeof options !== "string") { + const keys: string[] = []; + options.forEach((val, index) => { + keys.push(`${("000" + index).slice(-4)}. ${val}`); + }); + if (keys.every(v => !this.props.public_state.get(v))) { + this.setPublicState("error", "Field must be filled."); + this.setPublicState("valid", false); + } else { + this.setPublicState("error", ""); + this.setPublicState("valid", true); + } + } + break; + + case "radio": + this.setPublicState("valid", true); + this.setPublicState("error", ""); + break; + } } text_area_handler(event: ChangeEvent<HTMLTextAreaElement>): void { + // We will validate again when focusing out. + this.setPublicState("valid", true); + this.setPublicState("error", ""); + this.setPublicState("value", event.target.value); } + validateField(): void { + if (!this.props.question.required) { + return; + } + + let invalid = false; + const options: string | string[] = this.props.question.data["options"]; + switch (this.props.question.type) { + case QuestionType.TextArea: + case QuestionType.ShortText: + if (this.props.public_state.get("value") === "") { + invalid = true; + } + break; + + case QuestionType.Select: + case QuestionType.Range: + case QuestionType.Radio: + if (!this.props.public_state.get("value")) { + invalid = true; + } + break; + + case QuestionType.Checkbox: + if (typeof options !== "string") { + const keys: string[] = []; + options.forEach((val, index) => { + keys.push(`${("000" + index).slice(-4)}. ${val}`); + }); + if (keys.every(v => !this.props.public_state.get(v))) { + invalid = true; + } + } + break; + } + + if (invalid) { + this.setPublicState("error", "Field must be filled."); + this.setPublicState("valid", false); + } else { + this.setPublicState("error", ""); + this.setPublicState("valid", true); + } + } + componentDidMount(): void { // Initialize defaults for complex and nested fields const options: string | string[] = this.props.question.data["options"]; @@ -151,12 +249,22 @@ class RenderedQuestion extends React.Component<QuestionProp> { margin-left: 0.2rem; } `; + let valid = true; + if (!this.props.public_state.get("valid")) { + valid = false; + } + const rawError = this.props.public_state.get("error"); + let error = ""; + if (typeof rawError === "string") { + error = rawError; + } - return <div> + return <div ref={this.props.scroll_ref}> <h2 css={[selectable, requiredStarStyles]}> {question.name}<span className={question.required ? "required" : ""}>*</span> </h2> - { create_input(this.props, this.handler) } + { create_input(this.props, this.handler, this.blurHandler, this.props.focus_ref) } + <ErrorMessage show={!valid} message={error} /> <hr css={css`color: gray; margin: 3rem 0;`}/> </div>; } diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx index 4e13b8a..fa63282 100644 --- a/src/pages/FormPage.tsx +++ b/src/pages/FormPage.tsx @@ -2,8 +2,9 @@ import { jsx, css } from "@emotion/react"; import { Link } from "react-router-dom"; -import React, { SyntheticEvent, useEffect, useState } from "react"; +import React, { SyntheticEvent, useEffect, useState, createRef } from "react"; import { useParams } from "react-router"; +import { PropagateLoader } from "react-spinners"; import HeaderBar from "../components/HeaderBar"; import RenderedQuestion from "../components/Question"; @@ -14,8 +15,9 @@ import OAuth2Button from "../components/OAuth2Button"; import { Form, FormFeatures, getForm } from "../api/forms"; import { OAuthScopes, checkScopes } from "../api/auth"; import colors from "../colors"; -import { submitStyles, unselectable } from "../commonStyles"; - +import { submitStyles, unselectable } from "../commonStyles"; +import { Question, QuestionType } from "../api/question"; +import ApiClient from "../api/client"; interface PathParams { id: string @@ -27,13 +29,12 @@ interface NavigationProps { } class Navigation extends React.Component<NavigationProps> { - containerStyles = css` + static containerStyles = css` margin: auto; width: 50%; text-align: center; font-size: 1.5rem; - white-space: nowrap; > div { display: inline-block; @@ -70,12 +71,13 @@ class Navigation extends React.Component<NavigationProps> { } `; - returnStyles = css` - padding: 0.55rem 2.2rem; + static returnStyles = css` + padding: 0.5rem 2.2rem; border-radius: 8px; color: white; text-decoration: none; + white-space: nowrap; background-color: ${colors.greyple}; transition: background-color 300ms; @@ -83,7 +85,6 @@ class Navigation extends React.Component<NavigationProps> { :hover { background-color: ${colors.darkerGreyple}; } - } `; constructor(props: NavigationProps) { @@ -104,9 +105,9 @@ class Navigation extends React.Component<NavigationProps> { } return ( - <div css={[unselectable, this.containerStyles]}> + <div css={[unselectable, Navigation.containerStyles]}> <div className={ "return_button" + (this.props.form_state ? "" : " closed") }> - <Link to="/" css={this.returnStyles}>Return Home</Link> + <Link to="/" css={Navigation.returnStyles}>Return Home</Link> </div> <br css={this.separatorStyles}/> <div css={submitStyles}>{ submit }</div> @@ -144,6 +145,8 @@ function FormPage(): JSX.Element { const { id } = useParams<PathParams>(); const [form, setForm] = useState<Form>(); + const [sending, setSending] = useState<boolean>(); + const [sent, setSent] = useState<boolean>(); useEffect(() => { getForm(id).then(form => { @@ -151,26 +154,118 @@ function FormPage(): JSX.Element { }); }, []); + if (form && sent) { + const thanksStyle = css`font-family: "Uni Sans", "Hind", "Arial", sans-serif; margin-top: 15.5rem;`; + const divStyle = css`width: 80%;`; + return ( + <div> + <HeaderBar title={form.name} description={form.description}/> + <div css={[unselectable, Navigation.containerStyles, divStyle]}> + <h3 css={thanksStyle}>{form.submitted_text ?? "Thanks for your response!"}</h3> + <div className={ "return_button closed" }> + <Link to="/" css={Navigation.returnStyles}>Return Home</Link> + </div> + </div> + </div> + ); + } + + if (sending) { + return ( + <div> + <HeaderBar title={"Submitting..."}/> + <div css={{display: "flex", justifyContent: "center", paddingTop: "40px"}}> + <PropagateLoader color="white"/> + </div> + </div> + ); + } + if (!form) { return <Loading/>; } + const refMap: Map<string, React.RefObject<RenderedQuestion>> = new Map(); const questions = form.questions.map((question, index) => { - return <RenderedQuestion question={question} public_state={new Map()} key={index + Date.now()}/>; + const questionRef = createRef<RenderedQuestion>(); + refMap.set(question.id, questionRef); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return <RenderedQuestion ref={questionRef} focus_ref={createRef<any>()} scroll_ref={createRef<HTMLDivElement>()} question={question} public_state={new Map()} key={index + Date.now()}/>; }); - function handleSubmit(event: SyntheticEvent) { + async function handleSubmit(event: SyntheticEvent) { + event.preventDefault(); + // Client-side required validation + const invalidFieldIDs: number[] = []; + questions.forEach((prop, i) => { + const question: Question = prop.props.question; + if (!question.required) { + return; + } + + const questionRef = refMap.get(question.id); + if (questionRef && questionRef.current) { + questionRef.current.validateField(); + } + // In case when field is invalid, add this to invalid fields list. + if (prop.props.public_state.get("valid") === false) { + invalidFieldIDs.push(i); + } + }); + + if (invalidFieldIDs.length) { + const firstErrored = questions[invalidFieldIDs[0]]; + if (firstErrored && firstErrored.props.scroll_ref) { + // If any element is already focused, unfocus it to avoid not scrolling behavior. + if (document.activeElement && document.activeElement instanceof HTMLElement) { + document.activeElement.blur(); + } + + firstErrored.props.scroll_ref.current.scrollIntoView({ behavior: "smooth", block: "center" }); + if (firstErrored.props.focus_ref && firstErrored.props.focus_ref.current) { + firstErrored.props.focus_ref.current.focus({ preventScroll: true }); + } + } + return; + } + + setSending(true); + + const answers: { [key: string]: unknown } = {}; questions.forEach(prop => { - const question = prop.props.question; + const question: Question = prop.props.question; + const options: string | string[] = question.data["options"]; - // TODO: Parse input from each question, and submit + // Parse input from each question switch (question.type) { + case QuestionType.Section: + answers[question.id] = false; + break; + + case QuestionType.Checkbox: { + if (typeof options !== "string") { + const keys: Map<string, string> = new Map(); + options.forEach((val: string, index) => { + keys.set(val, `${("000" + index).slice(-4)}. ${val}`); + }); + const pairs: { [key: string]: boolean } = { }; + keys.forEach((val, key) => { + pairs[key] = !!prop.props.public_state.get(val); + }); + answers[question.id] = pairs; + } + break; + } + + case QuestionType.Code: default: - console.log(question.id, prop.props.public_state); + answers[question.id] = prop.props.public_state.get("value"); } }); - event.preventDefault(); + await ApiClient.post(`forms/submit/${id}`, {response: answers}); + setSending(false); + setSent(true); } const open: boolean = form.features.includes(FormFeatures.Open); diff --git a/src/tests/components/FormListing.test.tsx b/src/tests/components/FormListing.test.tsx index f269dbf..2116e48 100644 --- a/src/tests/components/FormListing.test.tsx +++ b/src/tests/components/FormListing.test.tsx @@ -21,7 +21,8 @@ const openFormListing: Form = { required: false } ], - webhook: null + webhook: null, + submitted_text: null }; const closedFormListing: Form = { @@ -38,7 +39,8 @@ const closedFormListing: Form = { required: false } ], - webhook: null + webhook: null, + submitted_text: null }; test("renders form listing with specified title", () => { diff --git a/src/tests/pages/LandingPage.test.tsx b/src/tests/pages/LandingPage.test.tsx index e461815..6f8a530 100644 --- a/src/tests/pages/LandingPage.test.tsx +++ b/src/tests/pages/LandingPage.test.tsx @@ -21,7 +21,8 @@ const testingForm: forms.Form = { required: true } ], - "webhook": null + "webhook": null, + submitted_text: null }; test("renders landing page", () => { |