aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Joe Banks <[email protected]>2020-10-05 13:13:51 +0100
committerGravatar GitHub <[email protected]>2020-10-05 13:13:51 +0100
commit91ef1e8d905e1ac68f6a3968f379d0675dfe6dcf (patch)
tree617e685d475acd15a7a6423d3a9b7826ee674f00
parentMerge pull request #14 from python-discord/api/add-dummy-forms (diff)
parentUpdate header test to include custom titles (diff)
Merge pull request #15 from python-discord/forms/add-form-page
Add specific form page
-rw-r--r--package.json1
-rw-r--r--src/App.tsx42
-rw-r--r--src/api/forms.ts32
-rw-r--r--src/api/question.ts11
-rw-r--r--src/components/FormListing.tsx6
-rw-r--r--src/components/HeaderBar/index.tsx36
-rw-r--r--src/globalStyles.ts40
-rw-r--r--src/pages/FormPage.tsx43
-rw-r--r--src/tests/components/FormListing.test.tsx8
-rw-r--r--src/tests/components/HeaderBar.test.tsx7
-rw-r--r--yarn.lock9
11 files changed, 166 insertions, 69 deletions
diff --git a/package.json b/package.json
index 98814fe..ff7968a 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
"react-inlinesvg": "^2.1.0",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.3",
+ "react-spinners": "^0.9.0",
"react-transition-group": "^4.4.1",
"typescript": "~3.7.2"
},
diff --git a/src/App.tsx b/src/App.tsx
index 05d8ded..9dd8b49 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,6 +1,6 @@
/** @jsx jsx */
/** @global location */
-import { css, jsx, Global } from "@emotion/core";
+import { jsx, Global } from "@emotion/core";
import {
BrowserRouter as Router,
@@ -11,49 +11,13 @@ import {
import { CSSTransition, TransitionGroup } from "react-transition-group";
import LandingPage from "./pages/LandingPage";
-import colors from "./colors";
import FormPage from "./pages/FormPage";
-const globalStyles = css`
-@import url('https://fonts.googleapis.com/css2?family=Hind:wght@700&display=swap');
-
-@font-face {
- font-family: 'Uni Sans';
- src: url(fonts/unisans.otf) format('opentype');
-}
-
-body {
- background-color: ${colors.notQuiteBlack};
- color: white;
- font-family: "Hind", "Helvetica", "Arial", sans-serif;
- margin: 0;
-}
-
-.fade-enter,
-.fade-exit {
- position: absolute;
- top: 0;
- left: 0;
- transition: 300ms ease-in-out opacity, 300ms ease-in-out transform;
- width: 100%;
-}
-
-.fade-enter,
-.fade-exit-active {
- opacity: 0;
- transform: scale(0.98);
-}
-
-.fade-enter-active {
- opacity: 1;
- z-index: 1;
- transform: scale(1);
-}
-`;
+import globalStyles from "./globalStyles";
const routes = [
{ path: "/", Component: LandingPage },
- { path: "/form", Component: FormPage}
+ { path: "/form/:id", Component: FormPage}
]
function App() {
diff --git a/src/api/forms.ts b/src/api/forms.ts
index 7c2666a..a4a4981 100644
--- a/src/api/forms.ts
+++ b/src/api/forms.ts
@@ -1,25 +1,53 @@
-export interface Form {
+import { Question, QuestionType } from "./question"
+
+export interface AllFormsForm {
title: string,
+ id: string,
description: string,
open: boolean
}
-export function getForms(): Form[] {
+export interface Form extends AllFormsForm {
+ questions: Array<Question>
+}
+
+export function getForms(): AllFormsForm[] {
return [
{
title: "Ban Appeals",
+ id: "ban-appeals",
description: "Appealing bans from the Discord server",
open: true
},
{
title: "Insights 2020",
+ id: "insights-2020",
description: "Insights about the Python Discord community",
open: false
},
{
title: "Code Jam 2099 Sign Ups",
+ id: "code-jam-2099-sign-up",
description: "Signing up for Python Discord's millionth code jam!",
open: false
}
]
}
+
+export function getForm(id: string): Promise<Form> {
+ const data: Form = {
+ title: "Ban Appeals",
+ id: "ban-appeals",
+ description: "Appealing bans from the Discord server",
+ open: true,
+ questions: [
+ {
+ name: "How Spanish are you?",
+ type: QuestionType.Text
+ }
+ ]
+ }
+ return new Promise((resolve) => {
+ setTimeout(() => resolve(data), 1500)
+ })
+}
diff --git a/src/api/question.ts b/src/api/question.ts
new file mode 100644
index 0000000..e051459
--- /dev/null
+++ b/src/api/question.ts
@@ -0,0 +1,11 @@
+export enum QuestionType {
+ Text,
+ Checkbox,
+ Radio,
+ Code
+}
+
+export interface Question {
+ name: string,
+ type: QuestionType
+}
diff --git a/src/components/FormListing.tsx b/src/components/FormListing.tsx
index dc761b6..2493608 100644
--- a/src/components/FormListing.tsx
+++ b/src/components/FormListing.tsx
@@ -9,10 +9,10 @@ import Tag from "./Tag";
import colors from "../colors";
-import { Form } from "../api/forms";
+import { AllFormsForm } from "../api/forms";
interface FormListingProps {
- form: Form
+ form: AllFormsForm
}
function FormListing({ form }: FormListingProps) {
@@ -43,7 +43,7 @@ function FormListing({ form }: FormListingProps) {
closedTag = <Tag text="CLOSED" color={colors.error}/>
};
- return <Link to="/form" css={listingStyle}>
+ return <Link to={`/form/${form.id}`} css={listingStyle}>
<div>
<h3 css={{fontSize: "1.5em", marginBottom: "0"}}>{closedTag}{form.title} <FontAwesomeIcon icon={faArrowRight} css={{fontSize: "0.75em", paddingBottom: "1px"}}/></h3>
<p css={{marginTop: "5px"}}>{form.description}</p>
diff --git a/src/components/HeaderBar/index.tsx b/src/components/HeaderBar/index.tsx
index 6289dfc..c3d46fc 100644
--- a/src/components/HeaderBar/index.tsx
+++ b/src/components/HeaderBar/index.tsx
@@ -5,6 +5,10 @@ import SVG from "react-inlinesvg";
import header1 from "./header_1.svg";
import header2 from "./header_2.svg";
+interface HeaderBarProps {
+ title?: string
+}
+
const headerImageStyles = css`
z-index: -1;
top: 0;
@@ -13,22 +17,22 @@ width: 100%;
transition: height 1s;
@media (max-width: 770px) {
- height: 180px;
-}
-
-@media (max-width: 580px) {
height: 140px;
}
`;
-function HeaderBar() {
+function HeaderBar({ title }: HeaderBarProps) {
+ if (!title) {
+ title = "Python Discord Forms";
+ };
+
return <div>
<div>
<SVG src={header1} css={headerImageStyles}/>
<SVG src={header2} css={headerImageStyles}/>
</div>
<h1 css={css`
- font-size: 4em;
+ font-size: 4vw;
margin: 0;
margin-top: 30px;
margin-left: 30px;
@@ -37,26 +41,22 @@ function HeaderBar() {
transition-duration: 1s;
font-family: "Uni Sans", "Hind", "Arial", sans-serif;
- @media (max-width: 770px) {
- margin-bottom: 100px;
- font-size: 3em;
+ @media (max-width: 1000px) {
+ margin-top: 15px;
+ font-size: 8vw;
}
- @media (max-width: 580px) {
- font-size: 2em;
+ @media (max-width: 770px) {
+ margin-top: 15px;
+ font-size: 6vw;
+ margin-bottom: 100px;
}
-
@media (max-width: 450px) {
- font-size: 1.70em;
text-align: center;
margin-left: 0;
}
-
- @media (max-width: 400px) {
- font-size: 1.3em;
- }
`}>
- Python Discord Forms
+ {title}
</h1>
</div>
}
diff --git a/src/globalStyles.ts b/src/globalStyles.ts
new file mode 100644
index 0000000..431ee36
--- /dev/null
+++ b/src/globalStyles.ts
@@ -0,0 +1,40 @@
+import { css } from "@emotion/core";
+
+import colors from "./colors";
+
+export default css`
+@import url('https://fonts.googleapis.com/css2?family=Hind:wght@700&display=swap');
+
+@font-face {
+ font-family: 'Uni Sans';
+ src: url(/fonts/unisans.otf) format('opentype');
+}
+
+body {
+ background-color: ${colors.notQuiteBlack};
+ color: white;
+ font-family: "Hind", "Helvetica", "Arial", sans-serif;
+ margin: 0;
+}
+
+.fade-enter,
+.fade-exit {
+ position: absolute;
+ top: 0;
+ left: 0;
+ transition: 300ms ease-in-out opacity, 300ms ease-in-out transform;
+ width: 100%;
+}
+
+.fade-enter,
+.fade-exit-active {
+ opacity: 0;
+ transform: scale(0.98);
+}
+
+.fade-enter-active {
+ opacity: 1;
+ z-index: 1;
+ transform: scale(1);
+}
+`;
diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index aa4cec3..45c093a 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -2,10 +2,47 @@
import { jsx } from "@emotion/core";
import { Link } from "react-router-dom";
+import { DotLoader } from "react-spinners";
+
+import { useParams } from "react-router";
+import HeaderBar from "../components/HeaderBar";
+import { useEffect, useState } from "react";
+import { Form, getForm } from "../api/forms";
+
+interface PathParams {
+ id: string
+}
+
+function Loading() {
+ return <div>
+ <HeaderBar title={"Loading..."}/>
+ <div css={{display: "flex", justifyContent: "center"}}>
+ <DotLoader color="white"/>
+ </div>
+ </div>
+}
+
function FormPage() {
- return <div css={{marginLeft: "20px"}}>
- <h1>Form page</h1>
- <Link to="/" css={{color: "white"}}>Go home</Link>
+ const { id } = useParams<PathParams>();
+
+ const [form, setForm] = useState<Form>();
+
+ useEffect(() => {
+ getForm(id).then(form => {
+ setForm(form);
+ })
+ })
+
+ if (!form) {
+ return <Loading/>
+ }
+
+ return <div>
+ <HeaderBar title={form.title}/>
+ <div css={{marginLeft: "20px"}}>
+ <h1>{form.description}</h1>
+ <Link to="/" css={{color: "white"}}>Return home</Link>
+ </div>
</div>
}
diff --git a/src/tests/components/FormListing.test.tsx b/src/tests/components/FormListing.test.tsx
index 4080f4d..82d1380 100644
--- a/src/tests/components/FormListing.test.tsx
+++ b/src/tests/components/FormListing.test.tsx
@@ -3,16 +3,18 @@ import { render } from '@testing-library/react';
import FormListing from "../../components/FormListing";
import { BrowserRouter as Router } from 'react-router-dom';
-import { Form } from '../../api/forms';
+import { AllFormsForm } from '../../api/forms';
-const openFormListing: Form = {
+const openFormListing: AllFormsForm = {
title: "Example form listing",
+ id: "example-form-listing",
description: "My form listing",
open: true
}
-const closedFormListing: Form = {
+const closedFormListing: AllFormsForm = {
title: "Example form listing",
+ id: "example-form-listing",
description: "My form listing",
open: false
}
diff --git a/src/tests/components/HeaderBar.test.tsx b/src/tests/components/HeaderBar.test.tsx
index 3567d7e..2e1f868 100644
--- a/src/tests/components/HeaderBar.test.tsx
+++ b/src/tests/components/HeaderBar.test.tsx
@@ -7,3 +7,10 @@ test('renders header bar with title', () => {
const formListing = getByText(/Python Discord Forms/i);
expect(formListing).toBeInTheDocument();
});
+
+test('renders header bar with custom title', () => {
+ const { getByText } = render(<HeaderBar title="Testing title"/>);
+ const formListing = getByText(/Testing title/i);
+ expect(formListing).toBeInTheDocument();
+});
+
diff --git a/yarn.lock b/yarn.lock
index 0c0f064..52d2ca8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1176,7 +1176,7 @@
"@emotion/utils" "0.11.3"
"@emotion/weak-memoize" "0.2.5"
-"@emotion/core@^10.0.35":
+"@emotion/core@^10.0.15", "@emotion/core@^10.0.35":
version "10.0.35"
resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.0.35.tgz#513fcf2e22cd4dfe9d3894ed138c9d7a859af9b3"
integrity sha512-sH++vJCdk025fBlRZSAhkRlSUoqSqgCzYf5fMOmqqi3bM6how+sQpg3hkgJonj8GxXM4WbD7dRO+4tegDB9fUw==
@@ -9045,6 +9045,13 @@ [email protected]:
optionalDependencies:
fsevents "2.1.2"
+react-spinners@^0.9.0:
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/react-spinners/-/react-spinners-0.9.0.tgz#b22c38acbfce580cd6f1b04a4649e812370b1fb8"
+ integrity sha512-+x6eD8tn/aYLdxZjNW7fSR1uoAXLb9qq6TFYZR1dFweJvckcf/HfP8Pa/cy5HOvB/cvI4JgrYXTjh2Me3S6Now==
+ dependencies:
+ "@emotion/core" "^10.0.15"
+
react-transition-group@^4.4.1:
version "4.4.1"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9"