From 0870589dab3fa46f59a1d6b128528c570da74cc7 Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Tue, 19 Jan 2021 14:14:38 +0200
Subject: Implement before-submit validation (broken, crashing)

---
 src/pages/FormPage.tsx | 36 ++++++++++++++++++++++++++++++++----
 1 file changed, 32 insertions(+), 4 deletions(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index c49b9fd..6c7cad2 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -2,7 +2,7 @@
 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, RefObject } from "react";
 import { useParams } from "react-router";
 
 import HeaderBar from "../components/HeaderBar";
@@ -13,6 +13,7 @@ import ScrollToTop from "../components/ScrollToTop";
 import { Form, FormFeatures, getForm } from "../api/forms";
 import colors from "../colors";
 import { unselectable }  from "../commonStyles";
+import { Question } from "../api/question";
 
 
 interface PathParams {
@@ -167,12 +168,36 @@ function FormPage(): JSX.Element {
         return <Loading/>;
     }
 
-    const questions = form.questions.map((question, index) => {
-        return <RenderedQuestion question={question} public_state={new Map()} key={index + Date.now()}/>;
+    const questionsMap: Map<string, JSX.Element> = new Map();
+    form.questions.map((question, index) => {
+        questionsMap.set(question.id, <RenderedQuestion ref={createRef<RenderedQuestion>()} scroll_ref={createRef<HTMLDivElement>()} question={question} public_state={new Map()} key={index + Date.now()}/>);
     });
 
     function handleSubmit(event: SyntheticEvent) {
-        questions.forEach(prop => {
+        // Client-side required validation
+        const invalidFieldIds: string[] = [];
+        questionsMap.forEach((prop, id) => {
+            const question: Question = prop.props.question;
+            if (!question.required) {
+                return;
+            }
+
+            prop.ref.current.validateField();
+            // In case when field is invalid, add this to invalid fields list.
+            if (prop.props.public_state.get("valid") === false) {
+                invalidFieldIds.push(id);
+            }
+        });
+
+        if (invalidFieldIds.length) {
+            const firstErrored = questionsMap.get(invalidFieldIds[0]);
+            if (firstErrored !== undefined) {
+                firstErrored.props.scroll_ref.current.scrollIntoView({ behavior: "smooth", block: "center" });
+            }
+            return;
+        }
+
+        questionsMap.forEach(prop => {
             const question = prop.props.question;
 
             // TODO: Parse input from each question, and submit
@@ -192,6 +217,9 @@ function FormPage(): JSX.Element {
         closed_header = <div css={closedHeaderStyles}>This form is now closed. You will not be able to submit your response.</div>;
     }
 
+    const questions: JSX.Element[] = [];
+    questionsMap.forEach(val => questions.push(val));
+
     return (
         <div>
             <HeaderBar title={form.name} description={form.description}/>
-- 
cgit v1.2.3


From 4cf4ae1a0195f0e0923ee48b428b94447e8f64b0 Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Tue, 19 Jan 2021 14:27:24 +0200
Subject: Add preventDefault to avoid reloading of page

---
 src/pages/FormPage.tsx | 1 +
 1 file changed, 1 insertion(+)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index 6c7cad2..1a9b7cf 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -174,6 +174,7 @@ function FormPage(): JSX.Element {
     });
 
     function handleSubmit(event: SyntheticEvent) {
+        event.preventDefault();
         // Client-side required validation
         const invalidFieldIds: string[] = [];
         questionsMap.forEach((prop, id) => {
-- 
cgit v1.2.3


From 3a2338e44b368defe441b91a9c0e60b6a679f871 Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Tue, 19 Jan 2021 14:33:35 +0200
Subject: Remove preventDefault from end

---
 src/pages/FormPage.tsx | 2 --
 1 file changed, 2 deletions(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index 1a9b7cf..06d20d6 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -207,8 +207,6 @@ function FormPage(): JSX.Element {
                     console.log(question.id, prop.props.public_state);
             }
         });
-
-        event.preventDefault();
     }
 
     const open: boolean = form.features.includes(FormFeatures.Open);
-- 
cgit v1.2.3


From 7db4972038dd1c27a75d50cd539f7d3c79e51bee Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Tue, 19 Jan 2021 15:29:49 +0200
Subject: Implement form submitting

---
 src/pages/FormPage.tsx | 33 ++++++++++++++++++++++++++++++---
 1 file changed, 30 insertions(+), 3 deletions(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index 06d20d6..dc023a6 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -13,7 +13,8 @@ import ScrollToTop from "../components/ScrollToTop";
 import { Form, FormFeatures, getForm } from "../api/forms";
 import colors from "../colors";
 import { unselectable }  from "../commonStyles";
-import { Question } from "../api/question";
+import { Question, QuestionType } from "../api/question";
+import ApiClient from "../api/client";
 
 
 interface PathParams {
@@ -173,7 +174,7 @@ function FormPage(): JSX.Element {
         questionsMap.set(question.id, <RenderedQuestion ref={createRef<RenderedQuestion>()} 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: string[] = [];
@@ -198,15 +199,41 @@ function FormPage(): JSX.Element {
             return;
         }
 
+        const answers = {};
         questionsMap.forEach(prop => {
             const question = prop.props.question;
+            const options: string | string[] = prop.props.question.data["options"];
 
             // TODO: Parse input from each question, and submit
             switch (question.type) {
+                case QuestionType.Section:
+                    answers[question.id] = false;
+                    break;
+
+                case QuestionType.Code:
+                    answers[question.id] = "";
+                    break;
+
+                case QuestionType.Checkbox:
+                    if (typeof options !== "string") {
+                        const keys: Map<string, string> = new Map();
+                        options.forEach((val, index) => {
+                            keys.set(val, `${("000" + index).slice(-4)}. ${val}`);
+                        });
+                        const pairs = {};
+                        keys.forEach((val, key) => {
+                            pairs[key] = !!prop.props.public_state.get(val);
+                        });
+                        answers[question.id] = pairs;
+                    }
+                    break;
+
                 default:
-                    console.log(question.id, prop.props.public_state);
+                    answers[question.id] = prop.props.public_state.get("value");
             }
         });
+
+        await ApiClient.post(`forms/submit/${id}`, {response: answers});
     }
 
     const open: boolean = form.features.includes(FormFeatures.Open);
-- 
cgit v1.2.3


From db9bc59c8b92141e1783629a345a6f7220417123 Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Tue, 19 Jan 2021 15:35:07 +0200
Subject: Un-refactor map to array for questions

---
 src/pages/FormPage.tsx | 18 +++++++-----------
 1 file changed, 7 insertions(+), 11 deletions(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index dc023a6..b4a8903 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -169,16 +169,15 @@ function FormPage(): JSX.Element {
         return <Loading/>;
     }
 
-    const questionsMap: Map<string, JSX.Element> = new Map();
-    form.questions.map((question, index) => {
-        questionsMap.set(question.id, <RenderedQuestion ref={createRef<RenderedQuestion>()} scroll_ref={createRef<HTMLDivElement>()} question={question} public_state={new Map()} key={index + Date.now()}/>);
+    const questions = form.questions.map((question, index) => {
+        return <RenderedQuestion ref={createRef<RenderedQuestion>()} scroll_ref={createRef<HTMLDivElement>()} question={question} public_state={new Map()} key={index + Date.now()}/>;
     });
 
     async function handleSubmit(event: SyntheticEvent) {
         event.preventDefault();
         // Client-side required validation
-        const invalidFieldIds: string[] = [];
-        questionsMap.forEach((prop, id) => {
+        const invalidFieldIds: number[] = [];
+        questions.forEach((prop, i) => {
             const question: Question = prop.props.question;
             if (!question.required) {
                 return;
@@ -187,12 +186,12 @@ function FormPage(): JSX.Element {
             prop.ref.current.validateField();
             // In case when field is invalid, add this to invalid fields list.
             if (prop.props.public_state.get("valid") === false) {
-                invalidFieldIds.push(id);
+                invalidFieldIds.push(i);
             }
         });
 
         if (invalidFieldIds.length) {
-            const firstErrored = questionsMap.get(invalidFieldIds[0]);
+            const firstErrored = questions[invalidFieldIds[0]];
             if (firstErrored !== undefined) {
                 firstErrored.props.scroll_ref.current.scrollIntoView({ behavior: "smooth", block: "center" });
             }
@@ -200,7 +199,7 @@ function FormPage(): JSX.Element {
         }
 
         const answers = {};
-        questionsMap.forEach(prop => {
+        questions.forEach(prop => {
             const question = prop.props.question;
             const options: string | string[] = prop.props.question.data["options"];
 
@@ -243,9 +242,6 @@ function FormPage(): JSX.Element {
         closed_header = <div css={closedHeaderStyles}>This form is now closed. You will not be able to submit your response.</div>;
     }
 
-    const questions: JSX.Element[] = [];
-    questionsMap.forEach(val => questions.push(val));
-
     return (
         <div>
             <HeaderBar title={form.name} description={form.description}/>
-- 
cgit v1.2.3


From a49bb796c7d4eee1f8184be78f1671bdf1cef61d Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Wed, 20 Jan 2021 13:27:21 +0200
Subject: Add state for displaying thanks for submitting showing

---
 src/commonStyles.tsx   |  63 +++++++++++++++++++++++++++++-
 src/pages/FormPage.tsx | 103 +++++++++++++++++++------------------------------
 2 files changed, 101 insertions(+), 65 deletions(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/commonStyles.tsx b/src/commonStyles.tsx
index 0cd68d5..3ff2a2f 100644
--- a/src/commonStyles.tsx
+++ b/src/commonStyles.tsx
@@ -60,11 +60,72 @@ const invalidStyles = css`
   }
 `;
 
+const containerStyles = css`
+  margin: auto;
+  width: 50%;
+
+  text-align: center;
+  font-size: 1.5rem;
+  white-space: nowrap;
+
+  > div {
+    display: inline-block;
+    margin: 2rem auto;
+    width: 50%;
+  }
+
+  @media (max-width: 850px) {
+    width: 100%;
+
+    > div {
+      display: flex;
+      justify-content: center;
+
+      margin: 0 auto;
+    }
+  }
+
+  .return_button {
+    text-align: left;
+  }
+
+  .return_button.closed {
+    text-align: center;
+  }
+`;
+
+const separatorStyles = css`
+  height: 0;
+  display: none;
+
+  @media (max-width: 850px) {
+    display: block;
+  }
+`;
+
+const returnStyles = css`
+  padding: 0.5rem 2rem;
+  border-radius: 8px;
+
+  color: white;
+  text-decoration: none;
+
+  background-color: ${colors.greyple};
+  transition: background-color 300ms;
+
+  :hover {
+    background-color: ${colors.darkerGreyple};
+  }
+`;
+
 export {
     selectable,
     unselectable,
     hiddenInput,
     multiSelectInput,
     textInputs,
-    invalidStyles
+    invalidStyles,
+    containerStyles,
+    separatorStyles,
+    returnStyles
 };
diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index b4a8903..cf6947b 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, createRef, RefObject } 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";
@@ -12,7 +13,7 @@ import ScrollToTop from "../components/ScrollToTop";
 
 import { Form, FormFeatures, getForm } from "../api/forms";
 import colors from "../colors";
-import { unselectable }  from "../commonStyles";
+import { unselectable, containerStyles, separatorStyles, returnStyles }  from "../commonStyles";
 import { Question, QuestionType } from "../api/question";
 import ApiClient from "../api/client";
 
@@ -26,65 +27,6 @@ interface NavigationProps {
 }
 
 class Navigation extends React.Component<NavigationProps> {
-    containerStyles = css`
-      margin: auto;
-      width: 50%;
-
-      text-align: center;
-      font-size: 1.5rem;
-      white-space: nowrap;
-
-      > div {
-        display: inline-block;
-        margin: 2rem auto;
-        width: 50%;
-      }
-
-      @media (max-width: 850px) {
-        width: 100%;
-
-        > div {
-          display: flex;
-          justify-content: center;
-
-          margin: 0 auto;
-        }
-      }
-
-      .return_button {
-        text-align: left;
-      }
-
-      .return_button.closed {
-        text-align: center;
-      }
-    `;
-
-    separatorStyles = css`
-      height: 0;
-      display: none;
-
-      @media (max-width: 850px) {
-        display: block;
-      }
-    `;
-
-    returnStyles = css`
-      padding: 0.5rem 2rem;
-      border-radius: 8px;
-
-      color: white;
-      text-decoration: none;
-
-      background-color: ${colors.greyple};
-      transition: background-color 300ms;
-
-      :hover {
-        background-color: ${colors.darkerGreyple};
-      }
-    }
-    `;
-
     submitStyles = css`
       text-align: right;
 
@@ -118,11 +60,11 @@ class Navigation extends React.Component<NavigationProps> {
         }
 
         return (
-            <div css={[unselectable, this.containerStyles]}>
+            <div css={[unselectable, containerStyles]}>
                 <div className={ "return_button" + (this.props.form_state ? "" : " closed") }>
-                    <Link to="/" css={this.returnStyles}>Return Home</Link>
+                    <Link to="/" css={returnStyles}>Return Home</Link>
                 </div>
-                <br css={this.separatorStyles}/>
+                <br css={separatorStyles}/>
                 { submit }
             </div>
         );
@@ -158,6 +100,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 => {
@@ -165,6 +109,33 @@ function FormPage(): JSX.Element {
         });
     }, []);
 
+    if (form && sent) {
+        const thanksStyle = css`font-family: "Uni Sans", "Hind", "Arial", sans-serif;`;
+        return (
+            <div>
+                <HeaderBar title={form.name} description={form.description}/>
+                <div css={[unselectable, containerStyles]}>
+                    <h3 css={thanksStyle}>Thanks for your response!</h3>
+                    <div className={ "return_button closed" }>
+                        <Link to="/" css={returnStyles}>Return Home</Link>
+                    </div>
+                    <br css={separatorStyles}/>
+                </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/>;
     }
@@ -198,6 +169,8 @@ function FormPage(): JSX.Element {
             return;
         }
 
+        setSending(true);
+
         const answers = {};
         questions.forEach(prop => {
             const question = prop.props.question;
@@ -233,6 +206,8 @@ function FormPage(): JSX.Element {
         });
 
         await ApiClient.post(`forms/submit/${id}`, {response: answers});
+        setSending(false);
+        setSent(true);
     }
 
     const open: boolean = form.features.includes(FormFeatures.Open);
-- 
cgit v1.2.3


From 449a56d91e7208b057a0a5165fbbc2bfadd33ba6 Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Thu, 21 Jan 2021 14:34:53 +0200
Subject: Implement dynamic showing of form submitted text

---
 src/commonStyles.tsx   | 2 +-
 src/pages/FormPage.tsx | 8 +++++---
 2 files changed, 6 insertions(+), 4 deletions(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/commonStyles.tsx b/src/commonStyles.tsx
index 3ff2a2f..cbfc40a 100644
--- a/src/commonStyles.tsx
+++ b/src/commonStyles.tsx
@@ -66,7 +66,6 @@ const containerStyles = css`
 
   text-align: center;
   font-size: 1.5rem;
-  white-space: nowrap;
 
   > div {
     display: inline-block;
@@ -109,6 +108,7 @@ const returnStyles = css`
 
   color: white;
   text-decoration: none;
+  white-space: nowrap;
 
   background-color: ${colors.greyple};
   transition: background-color 300ms;
diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index cf6947b..72b073f 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -29,6 +29,7 @@ interface NavigationProps {
 class Navigation extends React.Component<NavigationProps> {
     submitStyles = css`
       text-align: right;
+      white-space: nowrap;
 
       button {
         padding: 0.5rem 4rem;
@@ -110,12 +111,13 @@ function FormPage(): JSX.Element {
     }, []);
 
     if (form && sent) {
-        const thanksStyle = css`font-family: "Uni Sans", "Hind", "Arial", sans-serif;`;
+        const thanksStyle = css`font-family: "Uni Sans", "Hind", "Arial", sans-serif; margin-top: 250px;`;
+        const divStyle = css`width: 80%;`;
         return (
             <div>
                 <HeaderBar title={form.name} description={form.description}/>
-                <div css={[unselectable, containerStyles]}>
-                    <h3 css={thanksStyle}>Thanks for your response!</h3>
+                <div css={[unselectable, containerStyles, divStyle]}>
+                    <h3 css={thanksStyle}>{form.submitted_text ?? "Thanks for your response!"}</h3>
                     <div className={ "return_button closed" }>
                         <Link to="/" css={returnStyles}>Return Home</Link>
                     </div>
-- 
cgit v1.2.3


From 8d3469e69d1030b5d83108c6e967bffbb9e1d9a9 Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Thu, 21 Jan 2021 20:13:51 +0200
Subject: Use relative units

---
 src/commonStyles.tsx            | 4 ++--
 src/components/ErrorMessage.tsx | 6 +++---
 src/pages/FormPage.tsx          | 3 ++-
 3 files changed, 7 insertions(+), 6 deletions(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/commonStyles.tsx b/src/commonStyles.tsx
index cbfc40a..2caa77e 100644
--- a/src/commonStyles.tsx
+++ b/src/commonStyles.tsx
@@ -54,8 +54,8 @@ const textInputs = css`
 const invalidStyles = css`
   .invalid-box {
     -webkit-appearance: none;
-    -webkit-box-shadow: 0 0 10px ${colors.error};
-    box-shadow: 0 0 10px ${colors.error};
+    -webkit-box-shadow: 0 0 0.6rem ${colors.error};
+    box-shadow: 0 0 0.6rem ${colors.error};
     border: none;
   }
 `;
diff --git a/src/components/ErrorMessage.tsx b/src/components/ErrorMessage.tsx
index 55e3759..1cf3cbc 100644
--- a/src/components/ErrorMessage.tsx
+++ b/src/components/ErrorMessage.tsx
@@ -9,9 +9,9 @@ interface ErrorMessageProps {
 
 const styles = css`
   color: ${colors.error};
-  font-size: 18px;
-  line-height: 15px;
-  margin: 15px 0 0;
+  font-size: 1.15rem;
+  line-height: 1.1rem;
+  margin: 1rem 0 0;
 `;
 
 export default function ErrorMessage(props: ErrorMessageProps): JSX.Element|null {
diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index 72b073f..21303ab 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -107,11 +107,12 @@ function FormPage(): JSX.Element {
     useEffect(() => {
         getForm(id).then(form => {
             setForm(form);
+            setSent(true);
         });
     }, []);
 
     if (form && sent) {
-        const thanksStyle = css`font-family: "Uni Sans", "Hind", "Arial", sans-serif; margin-top: 250px;`;
+        const thanksStyle = css`font-family: "Uni Sans", "Hind", "Arial", sans-serif; margin-top: 15.5rem;`;
         const divStyle = css`width: 80%;`;
         return (
             <div>
-- 
cgit v1.2.3


From 646469028115dd7005e2a4427d55adc9f4150aa4 Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Sat, 23 Jan 2021 15:38:11 +0200
Subject: Remove debugging setSent

---
 src/pages/FormPage.tsx | 1 -
 1 file changed, 1 deletion(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index 21303ab..36ca86f 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -107,7 +107,6 @@ function FormPage(): JSX.Element {
     useEffect(() => {
         getForm(id).then(form => {
             setForm(form);
-            setSent(true);
         });
     }, []);
 
-- 
cgit v1.2.3


From e221e20a82411dabc4d6c21172f0c68badc64364 Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Thu, 28 Jan 2021 19:31:25 +0200
Subject: Remove unnecessary separator from sent form return home button

---
 src/commonStyles.tsx   | 10 ----------
 src/pages/FormPage.tsx | 12 ++++++++++--
 2 files changed, 10 insertions(+), 12 deletions(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/commonStyles.tsx b/src/commonStyles.tsx
index 2caa77e..1136b34 100644
--- a/src/commonStyles.tsx
+++ b/src/commonStyles.tsx
@@ -93,15 +93,6 @@ const containerStyles = css`
   }
 `;
 
-const separatorStyles = css`
-  height: 0;
-  display: none;
-
-  @media (max-width: 850px) {
-    display: block;
-  }
-`;
-
 const returnStyles = css`
   padding: 0.5rem 2rem;
   border-radius: 8px;
@@ -126,6 +117,5 @@ export {
     textInputs,
     invalidStyles,
     containerStyles,
-    separatorStyles,
     returnStyles
 };
diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index 36ca86f..abb008f 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -13,7 +13,7 @@ import ScrollToTop from "../components/ScrollToTop";
 
 import { Form, FormFeatures, getForm } from "../api/forms";
 import colors from "../colors";
-import { unselectable, containerStyles, separatorStyles, returnStyles }  from "../commonStyles";
+import { unselectable, containerStyles, returnStyles }  from "../commonStyles";
 import { Question, QuestionType } from "../api/question";
 import ApiClient from "../api/client";
 
@@ -27,6 +27,15 @@ interface NavigationProps {
 }
 
 class Navigation extends React.Component<NavigationProps> {
+    separatorStyles = css`
+      height: 0;
+      display: none;
+
+      @media (max-width: 850px) {
+        display: block;
+      }
+    `;
+
     submitStyles = css`
       text-align: right;
       white-space: nowrap;
@@ -121,7 +130,6 @@ function FormPage(): JSX.Element {
                     <div className={ "return_button closed" }>
                         <Link to="/" css={returnStyles}>Return Home</Link>
                     </div>
-                    <br css={separatorStyles}/>
                 </div>
             </div>
         );
-- 
cgit v1.2.3


From 978754f9bc81d0d836ddea6656af4a3dadce5248 Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Thu, 28 Jan 2021 19:34:15 +0200
Subject: Move container and return styles back to FormPage

---
 src/commonStyles.tsx   | 53 +-------------------------------------------------
 src/pages/FormPage.tsx | 52 +++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 51 insertions(+), 54 deletions(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/commonStyles.tsx b/src/commonStyles.tsx
index 1136b34..57002a9 100644
--- a/src/commonStyles.tsx
+++ b/src/commonStyles.tsx
@@ -60,62 +60,11 @@ const invalidStyles = css`
   }
 `;
 
-const containerStyles = css`
-  margin: auto;
-  width: 50%;
-
-  text-align: center;
-  font-size: 1.5rem;
-
-  > div {
-    display: inline-block;
-    margin: 2rem auto;
-    width: 50%;
-  }
-
-  @media (max-width: 850px) {
-    width: 100%;
-
-    > div {
-      display: flex;
-      justify-content: center;
-
-      margin: 0 auto;
-    }
-  }
-
-  .return_button {
-    text-align: left;
-  }
-
-  .return_button.closed {
-    text-align: center;
-  }
-`;
-
-const returnStyles = css`
-  padding: 0.5rem 2rem;
-  border-radius: 8px;
-
-  color: white;
-  text-decoration: none;
-  white-space: nowrap;
-
-  background-color: ${colors.greyple};
-  transition: background-color 300ms;
-
-  :hover {
-    background-color: ${colors.darkerGreyple};
-  }
-`;
-
 export {
     selectable,
     unselectable,
     hiddenInput,
     multiSelectInput,
     textInputs,
-    invalidStyles,
-    containerStyles,
-    returnStyles
+    invalidStyles
 };
diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index abb008f..de80e8a 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -13,10 +13,58 @@ import ScrollToTop from "../components/ScrollToTop";
 
 import { Form, FormFeatures, getForm } from "../api/forms";
 import colors from "../colors";
-import { unselectable, containerStyles, returnStyles }  from "../commonStyles";
+import { unselectable }  from "../commonStyles";
 import { Question, QuestionType } from "../api/question";
 import ApiClient from "../api/client";
 
+const containerStyles = css`
+  margin: auto;
+  width: 50%;
+
+  text-align: center;
+  font-size: 1.5rem;
+
+  > div {
+    display: inline-block;
+    margin: 2rem auto;
+    width: 50%;
+  }
+
+  @media (max-width: 850px) {
+    width: 100%;
+
+    > div {
+      display: flex;
+      justify-content: center;
+
+      margin: 0 auto;
+    }
+  }
+
+  .return_button {
+    text-align: left;
+  }
+
+  .return_button.closed {
+    text-align: center;
+  }
+`;
+
+const returnStyles = css`
+  padding: 0.5rem 2rem;
+  border-radius: 8px;
+
+  color: white;
+  text-decoration: none;
+  white-space: nowrap;
+
+  background-color: ${colors.greyple};
+  transition: background-color 300ms;
+
+  :hover {
+    background-color: ${colors.darkerGreyple};
+  }
+`;
 
 interface PathParams {
     id: string
@@ -74,7 +122,7 @@ class Navigation extends React.Component<NavigationProps> {
                 <div className={ "return_button" + (this.props.form_state ? "" : " closed") }>
                     <Link to="/" css={returnStyles}>Return Home</Link>
                 </div>
-                <br css={separatorStyles}/>
+                <br css={this.separatorStyles}/>
                 { submit }
             </div>
         );
-- 
cgit v1.2.3


From ff1e4bc4d37fb55aeb5b33cbb8b4f640e9fc745e Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Mon, 8 Feb 2021 16:31:29 +0200
Subject: Improve and simplify checkboxes gathering

Co-authored-by: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com>
---
 src/pages/FormPage.tsx | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index de80e8a..b8518c0 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -244,19 +244,18 @@ function FormPage(): JSX.Element {
                     answers[question.id] = "";
                     break;
 
-                case QuestionType.Checkbox:
-                    if (typeof options !== "string") {
-                        const keys: Map<string, string> = new Map();
-                        options.forEach((val, index) => {
-                            keys.set(val, `${("000" + index).slice(-4)}. ${val}`);
-                        });
-                        const pairs = {};
-                        keys.forEach((val, key) => {
-                            pairs[key] = !!prop.props.public_state.get(val);
-                        });
-                        answers[question.id] = pairs;
-                    }
+                case QuestionType.Checkbox: {
+                    const parsed = new Map();
+
+                    prop.props.public_state.forEach((value, key) => {
+                        if (key !== "valid" && key !== "error") {
+                            answers.set(key.slice(6), value);
+                        }
+                    });
+
+                    answers[question.id] = parsed;
                     break;
+                }
 
                 default:
                     answers[question.id] = prop.props.public_state.get("value");
-- 
cgit v1.2.3


From c9d423d99a0eb4be2b4cc808ae11e42fc2cd04de Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Mon, 8 Feb 2021 16:45:33 +0200
Subject: Simplify if check

---
 src/pages/FormPage.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index b8518c0..0023db4 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -221,7 +221,7 @@ function FormPage(): JSX.Element {
 
         if (invalidFieldIds.length) {
             const firstErrored = questions[invalidFieldIds[0]];
-            if (firstErrored !== undefined) {
+            if (firstErrored) {
                 firstErrored.props.scroll_ref.current.scrollIntoView({ behavior: "smooth", block: "center" });
             }
             return;
-- 
cgit v1.2.3


From c7711d4d14cfb8bd99ab066bf53ed5ef6efe6a9c Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Mon, 8 Feb 2021 16:47:58 +0200
Subject: Add nullability check for ref

---
 src/pages/FormPage.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index 0023db4..e8d1a4b 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -221,7 +221,7 @@ function FormPage(): JSX.Element {
 
         if (invalidFieldIds.length) {
             const firstErrored = questions[invalidFieldIds[0]];
-            if (firstErrored) {
+            if (firstErrored && firstErrored.props.scroll_ref) {
                 firstErrored.props.scroll_ref.current.scrollIntoView({ behavior: "smooth", block: "center" });
             }
             return;
-- 
cgit v1.2.3


From ee94923ffbe84361d1b8d219a8ed2e1d7a08e6a2 Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Mon, 8 Feb 2021 17:55:46 +0200
Subject: Improve submit data gathering

---
 src/pages/FormPage.tsx | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index e8d1a4b..ab74be9 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -229,10 +229,9 @@ function FormPage(): JSX.Element {
 
         setSending(true);
 
-        const answers = {};
+        const answers: { [key: string]: unknown } = {};
         questions.forEach(prop => {
-            const question = prop.props.question;
-            const options: string | string[] = prop.props.question.data["options"];
+            const question: Question = prop.props.question;
 
             // TODO: Parse input from each question, and submit
             switch (question.type) {
@@ -240,16 +239,12 @@ function FormPage(): JSX.Element {
                     answers[question.id] = false;
                     break;
 
-                case QuestionType.Code:
-                    answers[question.id] = "";
-                    break;
-
                 case QuestionType.Checkbox: {
-                    const parsed = new Map();
+                    const parsed: { [key: string]: unknown } = {};
 
-                    prop.props.public_state.forEach((value, key) => {
+                    prop.props.public_state.forEach((value: unknown, key: string) => {
                         if (key !== "valid" && key !== "error") {
-                            answers.set(key.slice(6), value);
+                            parsed[key.slice(6)] = value;
                         }
                     });
 
@@ -257,6 +252,7 @@ function FormPage(): JSX.Element {
                     break;
                 }
 
+                case QuestionType.Code:
                 default:
                     answers[question.id] = prop.props.public_state.get("value");
             }
-- 
cgit v1.2.3


From 4cd5c97fa8db2809c796f89062d06eade582ea55 Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Mon, 8 Feb 2021 18:01:08 +0200
Subject: Rename invalid field IDs variable

---
 src/pages/FormPage.tsx | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index ab74be9..8e998c5 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -205,7 +205,7 @@ function FormPage(): JSX.Element {
     async function handleSubmit(event: SyntheticEvent) {
         event.preventDefault();
         // Client-side required validation
-        const invalidFieldIds: number[] = [];
+        const invalidFieldIDs: number[] = [];
         questions.forEach((prop, i) => {
             const question: Question = prop.props.question;
             if (!question.required) {
@@ -215,12 +215,12 @@ function FormPage(): JSX.Element {
             prop.ref.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);
+                invalidFieldIDs.push(i);
             }
         });
 
-        if (invalidFieldIds.length) {
-            const firstErrored = questions[invalidFieldIds[0]];
+        if (invalidFieldIDs.length) {
+            const firstErrored = questions[invalidFieldIDs[0]];
             if (firstErrored && firstErrored.props.scroll_ref) {
                 firstErrored.props.scroll_ref.current.scrollIntoView({ behavior: "smooth", block: "center" });
             }
-- 
cgit v1.2.3


From 7075e8579e5aa038438be9bbb2ba275d52c20910 Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Mon, 8 Feb 2021 19:29:37 +0200
Subject: Implement focusing text fields if empty on submit

---
 src/components/InputTypes/ShortText.tsx | 6 ++++--
 src/components/InputTypes/TextArea.tsx  | 6 ++++--
 src/components/InputTypes/index.tsx     | 9 +++++----
 src/components/Question.tsx             | 6 ++++--
 src/pages/FormPage.tsx                  | 6 +++++-
 5 files changed, 22 insertions(+), 11 deletions(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/components/InputTypes/ShortText.tsx b/src/components/InputTypes/ShortText.tsx
index 5509a45..12f066e 100644
--- a/src/components/InputTypes/ShortText.tsx
+++ b/src/components/InputTypes/ShortText.tsx
@@ -6,13 +6,15 @@ import { textInputs, invalidStyles } from "../../commonStyles";
 interface ShortTextProps {
     handler: (event: ChangeEvent<HTMLInputElement>) => void,
     blurHandler: (event: FocusEvent<HTMLInputElement>) => void,
-    valid: boolean
+    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 (
         <div css={invalidStyles}>
-            <input type="text" css={textInputs} placeholder="Enter Text..." onChange={props.handler} onBlur={props.blurHandler} className={!props.valid ? "invalid-box" : ""}/>
+            <input type="text" css={textInputs} placeholder="Enter Text..." onChange={props.handler} onBlur={props.blurHandler} 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 10dbf10..35afe67 100644
--- a/src/components/InputTypes/TextArea.tsx
+++ b/src/components/InputTypes/TextArea.tsx
@@ -6,7 +6,9 @@ import { invalidStyles, textInputs } from "../../commonStyles";
 interface TextAreaProps {
     handler: (event: ChangeEvent<HTMLTextAreaElement>) => void,
     onBlurHandler: (event: FocusEvent<HTMLTextAreaElement>) => void,
-    valid: boolean
+    valid: boolean,
+    // eslint-disable-next-line @typescript-eslint/no-explicit-any
+    focus_ref: React.RefObject<any>
 }
 
 const styles = css`
@@ -21,7 +23,7 @@ const styles = css`
 export default function TextArea(props: TextAreaProps): JSX.Element {
     return (
         <div css={invalidStyles}>
-            <textarea css={[textInputs, styles]} placeholder="Enter Text..." onChange={props.handler} onBlur={props.onBlurHandler} className={!props.valid ? "invalid-box" : ""}/>
+            <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 2b348e0..cbfbd8c 100644
--- a/src/components/InputTypes/index.tsx
+++ b/src/components/InputTypes/index.tsx
@@ -18,7 +18,8 @@ const require_options: Array<QuestionType> = [
     QuestionType.Range
 ];
 
-export default function create_input({ question, public_state }: QuestionProp, handler: (event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void, blurHandler: () => 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, blurHandler: () => void, focus_ref: React.RefObject<any>): JSX.Element | JSX.Element[] {
     let result: JSX.Element | JSX.Element[];
 
     // eslint-disable-next-line
@@ -38,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} valid={valid} onBlurHandler={blurHandler}/>;
+            result = <TextArea handler={handler} valid={valid} onBlurHandler={blurHandler} focus_ref={focus_ref}/>;
             break;
 
         case QuestionType.Checkbox:
@@ -54,7 +55,7 @@ export default function create_input({ question, public_state }: QuestionProp, h
             break;
 
         case QuestionType.ShortText:
-            result = <ShortText handler={handler} blurHandler={blurHandler} valid={valid}/>;
+            result = <ShortText handler={handler} blurHandler={blurHandler} valid={valid} focus_ref={focus_ref}/>;
             break;
 
         case QuestionType.Range:
@@ -67,7 +68,7 @@ export default function create_input({ question, public_state }: QuestionProp, h
             break;
 
         default:
-            result = <TextArea handler={handler} valid={valid} onBlurHandler={blurHandler}/>;
+            result = <TextArea handler={handler} valid={valid} onBlurHandler={blurHandler} focus_ref={focus_ref}/>;
     }
     /* eslint-enable react/react-in-jsx-scope */
 
diff --git a/src/components/Question.tsx b/src/components/Question.tsx
index 567da2c..e619a45 100644
--- a/src/components/Question.tsx
+++ b/src/components/Question.tsx
@@ -18,7 +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>
+    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> {
@@ -256,7 +258,7 @@ class RenderedQuestion extends React.Component<QuestionProp> {
                 <h2 css={[selectable, requiredStarStyles]}>
                     {question.name}<span className={question.required ? "required" : ""}>*</span>
                 </h2>
-                { create_input(this.props, this.handler, this.blurHandler) }
+                { 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 8e998c5..50f48ba 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -199,7 +199,8 @@ function FormPage(): JSX.Element {
     }
 
     const questions = form.questions.map((question, index) => {
-        return <RenderedQuestion ref={createRef<RenderedQuestion>()} scroll_ref={createRef<HTMLDivElement>()} question={question} public_state={new Map()} key={index + Date.now()}/>;
+        // eslint-disable-next-line @typescript-eslint/no-explicit-any
+        return <RenderedQuestion ref={createRef<RenderedQuestion>()} focus_ref={createRef<any>()} scroll_ref={createRef<HTMLDivElement>()} question={question} public_state={new Map()} key={index + Date.now()}/>;
     });
 
     async function handleSubmit(event: SyntheticEvent) {
@@ -223,6 +224,9 @@ function FormPage(): JSX.Element {
             const firstErrored = questions[invalidFieldIDs[0]];
             if (firstErrored && firstErrored.props.scroll_ref) {
                 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;
         }
-- 
cgit v1.2.3


From da34ee3a362c04a52ea4c0d1f8e353aec8ab34ab Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Mon, 8 Feb 2021 19:35:57 +0200
Subject: Create refMap to avoid errors on direct ref access

---
 src/pages/FormPage.tsx | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index 50f48ba..7798be6 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -197,10 +197,13 @@ function FormPage(): JSX.Element {
     if (!form) {
         return <Loading/>;
     }
-
+    
+    const refMap: Map<string, React.RefObject<RenderedQuestion>> = new Map();
     const questions = form.questions.map((question, index) => {
+        const questionRef = createRef<RenderedQuestion>();
+        refMap.set(question.id, questionRef);
         // eslint-disable-next-line @typescript-eslint/no-explicit-any
-        return <RenderedQuestion ref={createRef<RenderedQuestion>()} focus_ref={createRef<any>()} scroll_ref={createRef<HTMLDivElement>()} question={question} public_state={new Map()} key={index + Date.now()}/>;
+        return <RenderedQuestion ref={questionRef} focus_ref={createRef<any>()} scroll_ref={createRef<HTMLDivElement>()} question={question} public_state={new Map()} key={index + Date.now()}/>;
     });
 
     async function handleSubmit(event: SyntheticEvent) {
@@ -213,7 +216,10 @@ function FormPage(): JSX.Element {
                 return;
             }
 
-            prop.ref.current.validateField();
+            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);
-- 
cgit v1.2.3


From 20a1d2dfb810cdbed70514d3917e95ef620cfc78 Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Mon, 8 Feb 2021 19:50:25 +0200
Subject: Remove trailing whitespaces

---
 src/components/Question.tsx | 6 +++---
 src/pages/FormPage.tsx      | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/components/Question.tsx b/src/components/Question.tsx
index e619a45..9a15a07 100644
--- a/src/components/Question.tsx
+++ b/src/components/Question.tsx
@@ -99,7 +99,7 @@ class RenderedQuestion extends React.Component<QuestionProp> {
             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") {
@@ -135,13 +135,13 @@ class RenderedQuestion extends React.Component<QuestionProp> {
         let invalid = false;
         const options: string | string[] = this.props.question.data["options"];
         switch (this.props.question.type) {
-            case QuestionType.TextArea:    
+            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:
diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index 7798be6..f0fb548 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -197,7 +197,7 @@ function FormPage(): JSX.Element {
     if (!form) {
         return <Loading/>;
     }
-    
+
     const refMap: Map<string, React.RefObject<RenderedQuestion>> = new Map();
     const questions = form.questions.map((question, index) => {
         const questionRef = createRef<RenderedQuestion>();
-- 
cgit v1.2.3


From 0e4c5c5b16a96895047b69385436a5596691cf09 Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Wed, 17 Feb 2021 15:39:57 +0200
Subject: Unfocus currently focused element before scrolling to invalid
 question

---
 src/pages/FormPage.tsx | 5 +++++
 1 file changed, 5 insertions(+)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index f0fb548..64d21f0 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -229,6 +229,11 @@ function FormPage(): JSX.Element {
         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 });
-- 
cgit v1.2.3


From cfc097d66563620f641ff701dbba2b35050a537e Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Wed, 17 Feb 2021 15:57:21 +0200
Subject: Move CSS back under navigation class to avoid messy diff

---
 src/pages/FormPage.tsx | 104 ++++++++++++++++++++++++-------------------------
 1 file changed, 52 insertions(+), 52 deletions(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index 64d21f0..d5f37f4 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -17,64 +17,48 @@ import { unselectable }  from "../commonStyles";
 import { Question, QuestionType } from "../api/question";
 import ApiClient from "../api/client";
 
-const containerStyles = css`
-  margin: auto;
-  width: 50%;
-
-  text-align: center;
-  font-size: 1.5rem;
-
-  > div {
-    display: inline-block;
-    margin: 2rem auto;
-    width: 50%;
-  }
-
-  @media (max-width: 850px) {
-    width: 100%;
-
-    > div {
-      display: flex;
-      justify-content: center;
+interface PathParams {
+    id: string
+}
 
-      margin: 0 auto;
-    }
-  }
+interface NavigationProps {
+    form_state: boolean  // Whether the form is open or not
+}
 
-  .return_button {
-    text-align: left;
-  }
+class Navigation extends React.Component<NavigationProps> {
+    static containerStyles = css`
+      margin: auto;
+      width: 50%;
 
-  .return_button.closed {
-    text-align: center;
-  }
-`;
+      text-align: center;
+      font-size: 1.5rem;
 
-const returnStyles = css`
-  padding: 0.5rem 2rem;
-  border-radius: 8px;
+      > div {
+        display: inline-block;
+        margin: 2rem auto;
+        width: 50%;
+      }
 
-  color: white;
-  text-decoration: none;
-  white-space: nowrap;
+      @media (max-width: 850px) {
+        width: 100%;
 
-  background-color: ${colors.greyple};
-  transition: background-color 300ms;
+        > div {
+          display: flex;
+          justify-content: center;
 
-  :hover {
-    background-color: ${colors.darkerGreyple};
-  }
-`;
+          margin: 0 auto;
+        }
+      }
 
-interface PathParams {
-    id: string
-}
+      .return_button {
+        text-align: left;
+      }
 
-interface NavigationProps {
-    form_state: boolean  // Whether the form is open or not
-}
+      .return_button.closed {
+        text-align: center;
+      }
+    `;
 
-class Navigation extends React.Component<NavigationProps> {
     separatorStyles = css`
       height: 0;
       display: none;
@@ -84,6 +68,22 @@ class Navigation extends React.Component<NavigationProps> {
       }
     `;
 
+    static returnStyles = css`
+      padding: 0.5rem 2rem;
+      border-radius: 8px;
+
+      color: white;
+      text-decoration: none;
+      white-space: nowrap;
+
+      background-color: ${colors.greyple};
+      transition: background-color 300ms;
+
+      :hover {
+        background-color: ${colors.darkerGreyple};
+      }
+    `;
+
     submitStyles = css`
       text-align: right;
       white-space: nowrap;
@@ -118,9 +118,9 @@ class Navigation extends React.Component<NavigationProps> {
         }
 
         return (
-            <div css={[unselectable, containerStyles]}>
+            <div css={[unselectable, Navigation.containerStyles]}>
                 <div className={ "return_button" + (this.props.form_state ? "" : " closed") }>
-                    <Link to="/" css={returnStyles}>Return Home</Link>
+                    <Link to="/" css={Navigation.returnStyles}>Return Home</Link>
                 </div>
                 <br css={this.separatorStyles}/>
                 { submit }
@@ -173,10 +173,10 @@ function FormPage(): JSX.Element {
         return (
             <div>
                 <HeaderBar title={form.name} description={form.description}/>
-                <div css={[unselectable, containerStyles, divStyle]}>
+                <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={returnStyles}>Return Home</Link>
+                        <Link to="/" css={Navigation.returnStyles}>Return Home</Link>
                     </div>
                 </div>
             </div>
-- 
cgit v1.2.3


From 66d375b041a5d70a99b83d2101f0417f07457c31 Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Thu, 18 Feb 2021 08:10:07 +0200
Subject: Revert change of gathering checkbox values

---
 src/pages/FormPage.tsx | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index d5f37f4..516d937 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -247,6 +247,7 @@ function FormPage(): JSX.Element {
         const answers: { [key: string]: unknown } = {};
         questions.forEach(prop => {
             const question: Question = prop.props.question;
+            const options: string | string[] = question.data["options"];
 
             // TODO: Parse input from each question, and submit
             switch (question.type) {
@@ -255,15 +256,17 @@ function FormPage(): JSX.Element {
                     break;
 
                 case QuestionType.Checkbox: {
-                    const parsed: { [key: string]: unknown } = {};
-
-                    prop.props.public_state.forEach((value: unknown, key: string) => {
-                        if (key !== "valid" && key !== "error") {
-                            parsed[key.slice(6)] = value;
-                        }
-                    });
-
-                    answers[question.id] = parsed;
+                    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;
                 }
 
-- 
cgit v1.2.3


From 51cbd6c1b78e2a92e25e31d2a00725d5af4a08c7 Mon Sep 17 00:00:00 2001
From: ks129 <45097959+ks129@users.noreply.github.com>
Date: Thu, 18 Feb 2021 11:49:48 +0200
Subject: Remove TODO

---
 src/pages/FormPage.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/pages/FormPage.tsx')

diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index 516d937..1e331b9 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -249,7 +249,7 @@ function FormPage(): JSX.Element {
             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;
-- 
cgit v1.2.3

