aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--package.json1
-rw-r--r--src/api/client.ts6
-rw-r--r--src/api/forms.ts52
-rw-r--r--src/api/question.ts16
-rw-r--r--src/components/FormListing.tsx10
-rw-r--r--src/components/Loading.tsx17
-rw-r--r--src/pages/FormPage.tsx14
-rw-r--r--src/pages/LandingPage.tsx19
-rw-r--r--src/tests/api/forms.test.ts6
-rw-r--r--src/tests/components/FormListing.test.tsx31
-rw-r--r--src/tests/pages/LandingPage.test.tsx21
-rw-r--r--webpack.config.js3
-rw-r--r--yarn.lock12
13 files changed, 140 insertions, 68 deletions
diff --git a/package.json b/package.json
index ba58f62..e93d18d 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
"@types/react-transition-group": "^4.4.0",
"@typescript-eslint/eslint-plugin": "^2.10.0",
"@typescript-eslint/parser": "^2.10.0",
+ "axios": "^0.21.0",
"copy-webpack-plugin": "^6.2.1",
"eslint": "^6.6.0",
"eslint-config-react-app": "^5.2.1",
diff --git a/src/api/client.ts b/src/api/client.ts
new file mode 100644
index 0000000..32c1993
--- /dev/null
+++ b/src/api/client.ts
@@ -0,0 +1,6 @@
+import axios from "axios";
+
+
+export default axios.create({
+ baseURL: process.env.BACKEND_URL
+})
diff --git a/src/api/forms.ts b/src/api/forms.ts
index a4a4981..724d6b7 100644
--- a/src/api/forms.ts
+++ b/src/api/forms.ts
@@ -1,49 +1,39 @@
import { Question, QuestionType } from "./question"
+import ApiClient from "./client";
-export interface AllFormsForm {
- title: string,
- id: string,
- description: string,
- open: boolean
+export enum FormFeatures {
+ Discoverable = "DISCOVERABLE",
+ RequiresLogin = "REQUIRES_LOGIN",
+ Open = "OPEN",
+ CollectEmail = "COLLECT_EMAIL",
+ DisableAntispam = "DISABLE_ANTISPAM"
}
-export interface Form extends AllFormsForm {
- questions: Array<Question>
+export interface Form {
+ id: string,
+ features: Array<FormFeatures>,
+ questions: Array<Question>,
+ name: string,
+ description: string
}
-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 async function getForms(): Promise<Form[]> {
+ const resp = await ApiClient.get("forms/discoverable");
+ return resp.data;
}
export function getForm(id: string): Promise<Form> {
const data: Form = {
- title: "Ban Appeals",
+ name: "Ban Appeals",
id: "ban-appeals",
description: "Appealing bans from the Discord server",
- open: true,
+ features: [FormFeatures.Discoverable, FormFeatures.Open],
questions: [
{
+ id: "how-spanish-are-you",
name: "How Spanish are you?",
- type: QuestionType.Text
+ type: QuestionType.ShortText,
+ data: {}
}
]
}
diff --git a/src/api/question.ts b/src/api/question.ts
index e051459..bdd6b99 100644
--- a/src/api/question.ts
+++ b/src/api/question.ts
@@ -1,11 +1,17 @@
export enum QuestionType {
- Text,
- Checkbox,
- Radio,
- Code
+ TextArea = "textarea",
+ Checkbox = "checkbox",
+ Radio = "radio",
+ Code = "code",
+ Select = "select",
+ ShortText = "short_text",
+ Range = "range",
+ Section = "section"
}
export interface Question {
+ id: string,
name: string,
- type: QuestionType
+ type: QuestionType,
+ data: { [key: string]: any }
}
diff --git a/src/components/FormListing.tsx b/src/components/FormListing.tsx
index 2493608..c53cf67 100644
--- a/src/components/FormListing.tsx
+++ b/src/components/FormListing.tsx
@@ -9,15 +9,15 @@ import Tag from "./Tag";
import colors from "../colors";
-import { AllFormsForm } from "../api/forms";
+import { Form, FormFeatures } from "../api/forms";
interface FormListingProps {
- form: AllFormsForm
+ form: Form
}
function FormListing({ form }: FormListingProps) {
const listingStyle = css`
- background-color: ${form.open ? colors.success : colors.darkButNotBlack};
+ background-color: ${form.features.includes(FormFeatures.Open) ? colors.success : colors.darkButNotBlack};
width: 60%;
padding: 20px;
margin-top: 20px;
@@ -39,13 +39,13 @@ function FormListing({ form }: FormListingProps) {
let closedTag;
- if (!form.open) {
+ if (!form.features.includes(FormFeatures.Open)) {
closedTag = <Tag text="CLOSED" color={colors.error}/>
};
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>
+ <h3 css={{fontSize: "1.5em", marginBottom: "0"}}>{closedTag}{form.name} <FontAwesomeIcon icon={faArrowRight} css={{fontSize: "0.75em", paddingBottom: "1px"}}/></h3>
<p css={{marginTop: "5px"}}>{form.description}</p>
</div>
</Link>
diff --git a/src/components/Loading.tsx b/src/components/Loading.tsx
new file mode 100644
index 0000000..48dcdbc
--- /dev/null
+++ b/src/components/Loading.tsx
@@ -0,0 +1,17 @@
+/** @jsx jsx */
+import { jsx } from "@emotion/core";
+
+import { HashLoader } from "react-spinners";
+
+import HeaderBar from "../components/HeaderBar";
+
+function Loading() {
+ return <div>
+ <HeaderBar title={"Loading..."}/>
+ <div css={{display: "flex", justifyContent: "center"}}>
+ <HashLoader color="white"/>
+ </div>
+ </div>
+}
+
+export default Loading;
diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index a675f8e..ad746c7 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -2,26 +2,16 @@
import { jsx } from "@emotion/core";
import { Link } from "react-router-dom";
-import { HashLoader } from "react-spinners";
-
import { useParams } from "react-router";
import HeaderBar from "../components/HeaderBar";
import { useEffect, useState } from "react";
import { Form, getForm } from "../api/forms";
+import Loading from "../components/Loading";
interface PathParams {
id: string
}
-function Loading() {
- return <div>
- <HeaderBar title={"Loading..."}/>
- <div css={{display: "flex", justifyContent: "center"}}>
- <HashLoader color="white"/>
- </div>
- </div>
-}
-
function FormPage() {
const { id } = useParams<PathParams>();
@@ -38,7 +28,7 @@ function FormPage() {
}
return <div>
- <HeaderBar title={form.title}/>
+ <HeaderBar title={form.name}/>
<div css={{marginLeft: "20px"}}>
<h1>{form.description}</h1>
<Link to="/" css={{color: "white"}}>Return home</Link>
diff --git a/src/pages/LandingPage.tsx b/src/pages/LandingPage.tsx
index 2e2bfd6..127f166 100644
--- a/src/pages/LandingPage.tsx
+++ b/src/pages/LandingPage.tsx
@@ -1,13 +1,28 @@
/** @jsx jsx */
import { css, jsx } from "@emotion/core";
+import { useEffect, useState } from "react";
import HeaderBar from "../components/HeaderBar";
import FormListing from "../components/FormListing";
-import { getForms } from "../api/forms";
+import { getForms, Form } from "../api/forms";
import OAuth2Button from "../components/OAuth2Button";
+import Loading from "../components/Loading";
function LandingPage() {
+ const [forms, setForms] = useState<Form[]>();
+
+ useEffect(() => {
+ const fetchForms = async () => {
+ setForms(await getForms());
+ }
+ fetchForms();
+ });
+
+ if (!forms) {
+ return <Loading/>;
+ }
+
return <div>
<HeaderBar/>
<div>
@@ -22,7 +37,7 @@ function LandingPage() {
<OAuth2Button/>
- {getForms().map(form => (
+ {forms.map(form => (
<FormListing key={form.id} form={form}/>
))}
</div>
diff --git a/src/tests/api/forms.test.ts b/src/tests/api/forms.test.ts
index 7c851a7..6e63965 100644
--- a/src/tests/api/forms.test.ts
+++ b/src/tests/api/forms.test.ts
@@ -1,11 +1,7 @@
import { getForm, getForms } from "../../api/forms";
-test('fetch a list of all forms', () => {
- expect(getForms()).toBeInstanceOf(Array);
-});
-
test('fetch a specific form', () => {
- expect(getForm("ban-appeals")).resolves.toHaveProperty("title", "Ban Appeals")
+ expect(getForm("ban-appeals")).resolves.toHaveProperty("name", "Ban Appeals")
});
export default null;
diff --git a/src/tests/components/FormListing.test.tsx b/src/tests/components/FormListing.test.tsx
index 5062a95..0afe10c 100644
--- a/src/tests/components/FormListing.test.tsx
+++ b/src/tests/components/FormListing.test.tsx
@@ -4,20 +4,37 @@ import '@testing-library/jest-dom/extend-expect';
import FormListing from "../../components/FormListing";
import { BrowserRouter as Router } from 'react-router-dom';
-import { AllFormsForm } from '../../api/forms';
+import { Form, FormFeatures } from '../../api/forms';
+import { QuestionType } from '../../api/question';
-const openFormListing: AllFormsForm = {
- title: "Example form listing",
+const openFormListing: Form = {
+ name: "Example form listing",
id: "example-form-listing",
description: "My form listing",
- open: true
+ features: [FormFeatures.Discoverable, FormFeatures.Open],
+ questions: [
+ {
+ "id": "my-question",
+ "name": "My question",
+ "type": QuestionType.ShortText,
+ "data": {}
+ }
+ ]
}
-const closedFormListing: AllFormsForm = {
- title: "Example form listing",
+const closedFormListing: Form = {
+ name: "Example form listing",
id: "example-form-listing",
description: "My form listing",
- open: false
+ features: [FormFeatures.Discoverable],
+ questions: [
+ {
+ "id": "what-should-i-ask",
+ "name": "What should I ask?",
+ "type": QuestionType.ShortText,
+ "data": {}
+ }
+ ]
}
test('renders form listing with specified title', () => {
diff --git a/src/tests/pages/LandingPage.test.tsx b/src/tests/pages/LandingPage.test.tsx
index ba32bab..23195bd 100644
--- a/src/tests/pages/LandingPage.test.tsx
+++ b/src/tests/pages/LandingPage.test.tsx
@@ -2,10 +2,31 @@ import React from 'react';
import { render } from '@testing-library/react';
import LandingPage from "../../pages/LandingPage";
+import * as forms from "../../api/forms";
import { BrowserRouter as Router } from "react-router-dom";
+import { QuestionType } from '../../api/question';
+
+const testingForm: forms.Form = {
+ "id": "testing-form",
+ "name": "Testing Form",
+ "description": "Meant for testing",
+ "features": [forms.FormFeatures.Discoverable],
+ "questions": [
+ {
+ "id": "my-question",
+ "name": "My Question",
+ "type": QuestionType.ShortText,
+ "data": {}
+ }
+ ]
+}
test('renders landing page', () => {
+ const setForms = jest.fn(() => [testingForm]);
+ Object.defineProperty(forms, "getForms", setForms);
+ const handleForms = jest.spyOn(React, "useState");
+ handleForms.mockImplementation(_value => [[testingForm], setForms]);
const { getByText } = render(<Router><LandingPage /></Router>);
// If we rendered the headerbar we rendered the landing page.
let headerBar = getByText(/Python Discord Forms/);
diff --git a/webpack.config.js b/webpack.config.js
index babea35..d2bf5aa 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -88,7 +88,8 @@ module.exports = (env) => {
REACT_APP_SHA: "development",
REACT_APP_SENTRY_DSN: "https://[email protected]/1234",
REACT_APP_BRANCH: "development",
- REACT_APP_OAUTH2_CLIENT_ID: "0"
+ REACT_APP_OAUTH2_CLIENT_ID: "0",
+ BACKEND_URL: "https://forms-api.pythondiscord.com/"
}),
new HtmlWebpackPlugin({
inject: true,
diff --git a/yarn.lock b/yarn.lock
index 9e3f2d6..0b46624 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2749,6 +2749,13 @@ axios@^0.18.0:
follow-redirects "1.5.10"
is-buffer "^2.0.2"
+axios@^0.21.0:
+ version "0.21.0"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.0.tgz#26df088803a2350dff2c27f96fef99fe49442aca"
+ integrity sha512-fmkJBknJKoZwem3/IKSSLpkdNXZeBu5Q7GA/aRsr2btgrptmSCxi2oFjZHqGdK9DoTil9PIHlPIZw2EcRJXRvw==
+ dependencies:
+ follow-redirects "^1.10.0"
+
axobject-query@^2.0.2:
version "2.2.0"
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
@@ -5311,6 +5318,11 @@ follow-redirects@^1.0.0:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
+follow-redirects@^1.10.0:
+ version "1.13.1"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.1.tgz#5f69b813376cee4fd0474a3aba835df04ab763b7"
+ integrity sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==
+
for-in@^0.1.3:
version "0.1.8"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1"