aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.eslintrc.json17
-rw-r--r--src/App.tsx76
-rw-r--r--src/api/client.ts2
-rw-r--r--src/api/forms.ts8
-rw-r--r--src/colors.ts14
-rw-r--r--src/components/FormListing.tsx26
-rw-r--r--src/components/HeaderBar/index.tsx26
-rw-r--r--src/components/Loading.tsx4
-rw-r--r--src/components/OAuth2Button.tsx66
-rw-r--r--src/components/Tag.tsx2
-rw-r--r--src/index.tsx72
-rw-r--r--src/pages/CallbackPage.tsx2
-rw-r--r--src/pages/FormPage.tsx10
-rw-r--r--src/pages/LandingPage.tsx48
-rw-r--r--src/react-app-env.d.ts30
-rw-r--r--src/serviceWorker.ts216
-rw-r--r--src/setupTests.ts2
-rw-r--r--src/tests/App.test.tsx6
-rw-r--r--src/tests/api/forms.test.ts6
-rw-r--r--src/tests/components/FormListing.test.tsx24
-rw-r--r--src/tests/components/HeaderBar.test.tsx10
-rw-r--r--src/tests/components/OAuth2Button.test.tsx10
-rw-r--r--src/tests/components/Tag.test.tsx12
-rw-r--r--src/tests/globalStyles.test.ts2
-rw-r--r--src/tests/pages/CallbackPage.test.tsx20
-rw-r--r--src/tests/pages/FormPage.test.tsx14
-rw-r--r--src/tests/pages/LandingPage.test.tsx14
27 files changed, 378 insertions, 361 deletions
diff --git a/.eslintrc.json b/.eslintrc.json
index 4e55622..5c7c77a 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -37,5 +37,20 @@
"error",
"always"
]
- }
+ },
+ "settings": {
+ "react": {
+ "pragma": "jsx",
+ "version": "detect",
+ "flowVersion": "0.53"
+ }
+ },
+ "overrides": [
+ {
+ "files": "*.test.ts*",
+ "rules": {
+ "react/react-in-jsx-scope": "off"
+ }
+ }
+ ]
}
diff --git a/src/App.tsx b/src/App.tsx
index b1b2184..523e583 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -4,9 +4,9 @@ import React, { Suspense } from "react";
import { jsx, css, Global } from "@emotion/react";
import {
- BrowserRouter as Router,
- Route,
- Switch
+ BrowserRouter as Router,
+ Route,
+ Switch
} from "react-router-dom";
import { PropagateLoader } from "react-spinners";
@@ -20,48 +20,48 @@ const FormPage = React.lazy(() => import("./pages/FormPage"));
const CallbackPage = React.lazy(() => import("./pages/CallbackPage"));
const routes = [
- { path: "/", Component: LandingPage },
- { path: "/form/:id", Component: FormPage},
- { path: "/callback", Component: CallbackPage }
-]
+ { path: "/", Component: LandingPage },
+ { path: "/form/:id", Component: FormPage},
+ { path: "/callback", Component: CallbackPage }
+];
function PageLoading() {
- return <div css={css`
+ return <div css={css`
display: flex;
justify-content: center;
margin-top: 50px;
`}>
- <PropagateLoader color="white" size={100}/>
- </div>
+ <PropagateLoader color="white" size={100}/>
+ </div>;
}
-function App() {
- return (
- <div>
- <Global styles={globalStyles}/>
- <Router>
- <Route render={({ location }) => (
- <TransitionGroup>
- <CSSTransition
- key={location.pathname}
- classNames="fade"
- timeout={300}
- >
- <Switch location={location}>
- {routes.map(({path, Component}) => (
- <Route exact key={path} path={path}>
- <Suspense fallback={<PageLoading/>}>
- <Component/>
- </Suspense>
- </Route>
- ))}
- </Switch>
- </CSSTransition>
- </TransitionGroup>
- )}/>
- </Router>
- </div>
- );
-};
+function App(): JSX.Element {
+ return (
+ <div>
+ <Global styles={globalStyles}/>
+ <Router>
+ <Route render={({ location }) => (
+ <TransitionGroup>
+ <CSSTransition
+ key={location.pathname}
+ classNames="fade"
+ timeout={300}
+ >
+ <Switch location={location}>
+ {routes.map(({path, Component}) => (
+ <Route exact key={path} path={path}>
+ <Suspense fallback={<PageLoading/>}>
+ <Component/>
+ </Suspense>
+ </Route>
+ ))}
+ </Switch>
+ </CSSTransition>
+ </TransitionGroup>
+ )}/>
+ </Router>
+ </div>
+ );
+}
export default App;
diff --git a/src/api/client.ts b/src/api/client.ts
index 32c1993..b534938 100644
--- a/src/api/client.ts
+++ b/src/api/client.ts
@@ -3,4 +3,4 @@ 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 724d6b7..aec4b99 100644
--- a/src/api/forms.ts
+++ b/src/api/forms.ts
@@ -1,4 +1,4 @@
-import { Question, QuestionType } from "./question"
+import { Question, QuestionType } from "./question";
import ApiClient from "./client";
export enum FormFeatures {
@@ -36,8 +36,8 @@ export function getForm(id: string): Promise<Form> {
data: {}
}
]
- }
+ };
return new Promise((resolve) => {
- setTimeout(() => resolve(data), 1500)
- })
+ setTimeout(() => resolve(data), 1500);
+ });
}
diff --git a/src/colors.ts b/src/colors.ts
index 2107987..e9c74b1 100644
--- a/src/colors.ts
+++ b/src/colors.ts
@@ -1,8 +1,8 @@
export default {
- blurple: '#7289DA',
- darkButNotBlack: '#2C2F33',
- notQuiteBlack: '#23272A',
- greyple: '#99AAB5',
- error: '#f04747',
- success: '#43b581'
-}
+ blurple: "#7289DA",
+ darkButNotBlack: "#2C2F33",
+ notQuiteBlack: "#23272A",
+ greyple: "#99AAB5",
+ error: "#f04747",
+ success: "#43b581"
+};
diff --git a/src/components/FormListing.tsx b/src/components/FormListing.tsx
index f53efe2..0905903 100644
--- a/src/components/FormListing.tsx
+++ b/src/components/FormListing.tsx
@@ -2,7 +2,7 @@
import { css, jsx } from "@emotion/react";
import { Link } from "react-router-dom";
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowRight } from "@fortawesome/free-solid-svg-icons";
import Tag from "./Tag";
@@ -15,8 +15,8 @@ interface FormListingProps {
form: Form
}
-function FormListing({ form }: FormListingProps) {
- const listingStyle = css`
+function FormListing({ form }: FormListingProps): JSX.Element {
+ const listingStyle = css`
background-color: ${form.features.includes(FormFeatures.Open) ? colors.success : colors.darkButNotBlack};
width: 60%;
padding: 20px;
@@ -37,18 +37,18 @@ function FormListing({ form }: FormListingProps) {
}
`;
- let closedTag;
+ let closedTag;
- if (!form.features.includes(FormFeatures.Open)) {
- closedTag = <Tag text="CLOSED" color={colors.error}/>
- };
+ 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.name} <FontAwesomeIcon icon={faArrowRight} css={{fontSize: "0.75em", paddingBottom: "1px"}}/></h3>
- <p css={{marginTop: "5px"}}>{form.description}</p>
- </div>
- </Link>
+ return <Link to={`/form/${form.id}`} css={listingStyle}>
+ <div>
+ <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>;
}
export default FormListing;
diff --git a/src/components/HeaderBar/index.tsx b/src/components/HeaderBar/index.tsx
index b789ddb..dfe3957 100644
--- a/src/components/HeaderBar/index.tsx
+++ b/src/components/HeaderBar/index.tsx
@@ -16,17 +16,17 @@ width: 100%;
transition: height 1s;
`;
-function HeaderBar({ title }: HeaderBarProps) {
- if (!title) {
- title = "Python Discord Forms";
- };
+function HeaderBar({ title }: HeaderBarProps): JSX.Element {
+ if (!title) {
+ title = "Python Discord Forms";
+ }
- return <div>
- <div>
- <Header1 css={headerImageStyles}/>
- <Header2 css={headerImageStyles}/>
- </div>
- <h1 css={css`
+ return <div>
+ <div>
+ <Header1 css={headerImageStyles}/>
+ <Header2 css={headerImageStyles}/>
+ </div>
+ <h1 css={css`
font-size: 4vw;
margin: 0;
margin-top: 30px;
@@ -51,9 +51,9 @@ function HeaderBar({ title }: HeaderBarProps) {
margin-left: 0;
}
`}>
- {title}
- </h1>
- </div>
+ {title}
+ </h1>
+ </div>;
}
export default HeaderBar;
diff --git a/src/components/Loading.tsx b/src/components/Loading.tsx
index 8454366..8dd5474 100644
--- a/src/components/Loading.tsx
+++ b/src/components/Loading.tsx
@@ -5,13 +5,13 @@ import { PropagateLoader } from "react-spinners";
import HeaderBar from "../components/HeaderBar";
-function Loading() {
+function Loading(): JSX.Element {
return <div>
<HeaderBar title={"Loading..."}/>
<div css={{display: "flex", justifyContent: "center", paddingTop: "40px"}}>
<PropagateLoader color="white"/>
</div>
- </div>
+ </div>;
}
export default Loading;
diff --git a/src/components/OAuth2Button.tsx b/src/components/OAuth2Button.tsx
index c364369..4fa3f61 100644
--- a/src/components/OAuth2Button.tsx
+++ b/src/components/OAuth2Button.tsx
@@ -1,7 +1,7 @@
/** @jsx jsx */
import { css, jsx } from "@emotion/react";
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faDiscord } from "@fortawesome/free-brands-svg-icons";
import colors from "../colors";
@@ -40,49 +40,49 @@ span {
`;
function doLogin(disableFunction: (newState: boolean) => void) {
- disableFunction(true);
+ disableFunction(true);
- const redirectURI = encodeURIComponent(document.location.protocol + "//" + document.location.host + "/callback");
+ const redirectURI = encodeURIComponent(document.location.protocol + "//" + document.location.host + "/callback");
- const windowRef = window.open(
- `https://discord.com/api/oauth2/authorize?client_id=${OAUTH2_CLIENT_ID}&response_type=code&scope=identify&redirect_uri=${redirectURI}&prompt=none`,
- "Discord_OAuth2",
- "height=700,width=500,location=no,menubar=no,resizable=no,status=no,titlebar=no,left=300,top=300"
- )
+ const windowRef = window.open(
+ `https://discord.com/api/oauth2/authorize?client_id=${OAUTH2_CLIENT_ID}&response_type=code&scope=identify&redirect_uri=${redirectURI}&prompt=none`,
+ "Discord_OAuth2",
+ "height=700,width=500,location=no,menubar=no,resizable=no,status=no,titlebar=no,left=300,top=300"
+ );
- const interval = setInterval(() => {
- if (windowRef?.closed) {
- clearInterval(interval);
- disableFunction(false);
- }
- }, 500)
+ const interval = setInterval(() => {
+ if (windowRef?.closed) {
+ clearInterval(interval);
+ disableFunction(false);
+ }
+ }, 500);
- window.onmessage = (code: MessageEvent) => {
- if (code.data.source) {
- // React DevTools has a habit of sending messages, ignore them.
- return;
- }
+ window.onmessage = (code: MessageEvent) => {
+ if (code.data.source) {
+ // React DevTools has a habit of sending messages, ignore them.
+ return;
+ }
- if (code.isTrusted) {
- windowRef?.close();
+ if (code.isTrusted) {
+ windowRef?.close();
- console.log("Code received:", code.data);
+ console.log("Code received:", code.data);
- disableFunction(false);
- clearInterval(interval);
+ disableFunction(false);
+ clearInterval(interval);
- window.onmessage = null;
- }
- };
+ window.onmessage = null;
+ }
+ };
}
-function OAuth2Button() {
- const [disabled, setDisabled] = useState<boolean>(false);
+function OAuth2Button(): JSX.Element {
+ const [disabled, setDisabled] = useState<boolean>(false);
- return <button disabled={disabled} onClick={() => doLogin(setDisabled)} css={buttonStyling}>
- <span css={{marginRight: "10px"}}><FontAwesomeIcon icon={faDiscord} css={{fontSize: "2em", marginTop: "3px"}}/></span>
- <span>Sign in with Discord</span>
- </button>;
+ return <button disabled={disabled} onClick={() => doLogin(setDisabled)} css={buttonStyling}>
+ <span css={{marginRight: "10px"}}><FontAwesomeIcon icon={faDiscord} css={{fontSize: "2em", marginTop: "3px"}}/></span>
+ <span>Sign in with Discord</span>
+ </button>;
}
export default OAuth2Button;
diff --git a/src/components/Tag.tsx b/src/components/Tag.tsx
index 0c55348..3e5b1f5 100644
--- a/src/components/Tag.tsx
+++ b/src/components/Tag.tsx
@@ -7,7 +7,7 @@ interface TagProps {
fontSize?: string
}
-function Tag(props: TagProps) {
+function Tag(props: TagProps): JSX.Element {
return <span css={css`
font-size: ${props.fontSize ? props.fontSize : "0.75em"};
background-color: ${props.color};
diff --git a/src/index.tsx b/src/index.tsx
index 73e8120..871eb40 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,50 +1,52 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-import App from './App';
-import * as serviceWorker from './serviceWorker';
+import React from "react";
+import ReactDOM from "react-dom";
+import App from "./App";
+import * as serviceWorker from "./serviceWorker";
import * as Sentry from "@sentry/react";
import colors from "./colors";
if (process.env.NODE_ENV === "production") {
- Sentry.init({
- dsn: process.env.REACT_APP_SENTRY_DSN,
- tracesSampleRate: 0.25,
- release: `forms-frontend@${process.env.REACT_APP_SHA}`,
- environment: process.env.CONTEXT
- });
+ Sentry.init({
+ dsn: process.env.REACT_APP_SENTRY_DSN,
+ tracesSampleRate: 0.25,
+ release: `forms-frontend@${process.env.REACT_APP_SHA}`,
+ environment: process.env.CONTEXT
+ });
}
-console.log("%c Python Discord Forms ", `font-size: 6em; font-family: "Hind", "Arial"; font-weight: 900; background-color: ${colors.blurple}; border-radius: 10px;`)
-console.log("%cWelcome to Python Discord Forms", `font-size: 3em; font-family: "Hind", "Arial";`)
+console.log("%c Python Discord Forms ", `font-size: 6em; font-family: "Hind", "Arial"; font-weight: 900; background-color: ${colors.blurple}; border-radius: 10px;`);
+console.log("%cWelcome to Python Discord Forms", "font-size: 3em; font-family: \"Hind\", \"Arial\";");
-console.log(` Environment: %c ${process.env.NODE_ENV} `, `padding: 2px; border-radius: 5px; background-color: ${process.env.NODE_ENV === "production" ? colors.success : colors.error}`)
-console.log(` Context: %c ${process.env.CONTEXT} `, `padding: 2px; border-radius: 5px; background-color: ${process.env.CONTEXT === "production" ? colors.success : colors.error}`)
-console.log(` Location: %c ${document.location.pathname + document.location.search + document.location.hash} `, `padding: 2px; border-radius: 5px; background-color: ${colors.success}`)
-console.log(` User Agent: %c ${navigator.userAgent} `, `padding: 2px; border-radius: 5px; background-color: ${colors.success}`)
-console.log(` Branch: %c ${process.env.REACT_APP_BRANCH} `, `padding: 2px; border-radius: 5px; background-color: ${process.env.REACT_APP_BRANCH === "main" ? colors.success : colors.error}`)
-console.log(` SHA: %c ${process.env.REACT_APP_SHA} `, `padding: 2px; border-radius: 5px; background-color: ${colors.success}`)
+console.log(` Environment: %c ${process.env.NODE_ENV} `, `padding: 2px; border-radius: 5px; background-color: ${process.env.NODE_ENV === "production" ? colors.success : colors.error}`);
+console.log(` Context: %c ${process.env.CONTEXT} `, `padding: 2px; border-radius: 5px; background-color: ${process.env.CONTEXT === "production" ? colors.success : colors.error}`);
+console.log(` Location: %c ${document.location.pathname + document.location.search + document.location.hash} `, `padding: 2px; border-radius: 5px; background-color: ${colors.success}`);
+console.log(` User Agent: %c ${navigator.userAgent} `, `padding: 2px; border-radius: 5px; background-color: ${colors.success}`);
+console.log(` Branch: %c ${process.env.REACT_APP_BRANCH} `, `padding: 2px; border-radius: 5px; background-color: ${process.env.REACT_APP_BRANCH === "main" ? colors.success : colors.error}`);
+console.log(` SHA: %c ${process.env.REACT_APP_SHA} `, `padding: 2px; border-radius: 5px; background-color: ${colors.success}`);
-console.log("%cCome join us on Discord! https://discord.gg/python", `font-size: 1.5em; font-family: "Hind", "Arial"; color: ${colors.blurple}`)
+console.log("%cCome join us on Discord! https://discord.gg/python", `font-size: 1.5em; font-family: "Hind", "Arial"; color: ${colors.blurple}`);
+/* eslint-disable react/react-in-jsx-scope */
ReactDOM.render(
- <React.StrictMode>
- <Sentry.ErrorBoundary
- fallback={<p>An error has occurred with Python Discord Forms. Please let us know in the Discord server at <a href="https://discord.gg/python">discord.gg/python</a></p>}
- showDialog={true}
- dialogOptions={{
- title: "You've found a bug in PyDis forms!"
- }}
- onError={(err) => {
- if(process.env.NODE_ENV === "development")
- console.log(err)
- }}
- >
- <App />
- </Sentry.ErrorBoundary>
- </React.StrictMode>,
- document.getElementById('root')
+ <React.StrictMode>
+ <Sentry.ErrorBoundary
+ fallback={<p>An error has occurred with Python Discord Forms. Please let us know in the Discord server at <a href="https://discord.gg/python">discord.gg/python</a></p>}
+ showDialog={true}
+ dialogOptions={{
+ title: "You've found a bug in PyDis forms!"
+ }}
+ onError={(err) => {
+ if(process.env.NODE_ENV === "development")
+ console.log(err);
+ }}
+ >
+ <App />
+ </Sentry.ErrorBoundary>
+ </React.StrictMode>,
+ document.getElementById("root")
);
+/* eslint-enable react/react-in-jsx-scope */
serviceWorker.unregister();
diff --git a/src/pages/CallbackPage.tsx b/src/pages/CallbackPage.tsx
index 691a3e4..fab2086 100644
--- a/src/pages/CallbackPage.tsx
+++ b/src/pages/CallbackPage.tsx
@@ -2,7 +2,7 @@
import { jsx } from "@emotion/react";
import { useState } from "react";
-export default function CallbackPage() {
+export default function CallbackPage(): JSX.Element {
const [hasSent, setHasSent] = useState(false);
const params = new URLSearchParams(location.search);
diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index 97ff24d..1805897 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -12,7 +12,7 @@ interface PathParams {
id: string
}
-function FormPage() {
+function FormPage(): JSX.Element {
const { id } = useParams<PathParams>();
const [form, setForm] = useState<Form>();
@@ -20,11 +20,11 @@ function FormPage() {
useEffect(() => {
getForm(id).then(form => {
setForm(form);
- })
- })
+ });
+ });
if (!form) {
- return <Loading/>
+ return <Loading/>;
}
return <div>
@@ -33,7 +33,7 @@ function FormPage() {
<h1>{form.description}</h1>
<Link to="/" css={{color: "white"}}>Return home</Link>
</div>
- </div>
+ </div>;
}
export default FormPage;
diff --git a/src/pages/LandingPage.tsx b/src/pages/LandingPage.tsx
index 1320c14..124bbcf 100644
--- a/src/pages/LandingPage.tsx
+++ b/src/pages/LandingPage.tsx
@@ -9,40 +9,40 @@ 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());
+function LandingPage(): JSX.Element {
+ const [forms, setForms] = useState<Form[]>();
+
+ useEffect(() => {
+ const fetchForms = async () => {
+ setForms(await getForms());
+ };
+ fetchForms();
+ }, []);
+
+ if (!forms) {
+ return <Loading/>;
}
- fetchForms();
- }, []);
-
- if (!forms) {
- return <Loading/>;
- }
- return <div>
- <HeaderBar/>
- <div>
+ return <div>
+ <HeaderBar/>
+ <div>
- <div css={css`
+ <div css={css`
display: flex;
align-items: center;
flex-direction: column;
`}>
- <h1>Available Forms</h1>
+ <h1>Available Forms</h1>
- <OAuth2Button/>
+ <OAuth2Button/>
- {forms.map(form => (
- <FormListing key={form.id} form={form}/>
- ))}
- </div>
- </div>
- </div>
+ {forms.map(form => (
+ <FormListing key={form.id} form={form}/>
+ ))}
+ </div>
+ </div>
+ </div>;
}
export default LandingPage;
diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts
index 981cd73..d7e3ac4 100644
--- a/src/react-app-env.d.ts
+++ b/src/react-app-env.d.ts
@@ -1,46 +1,46 @@
-/// <reference types="node" />
-/// <reference types="react" />
-/// <reference types="react-dom" />
+import("node");
+import("react");
+import("react-dom");
declare namespace NodeJS {
interface ProcessEnv {
- readonly NODE_ENV: 'development' | 'production' | 'test';
+ readonly NODE_ENV: "development" | "production" | "test";
readonly PUBLIC_URL: string;
}
}
-declare module '*.bmp' {
+declare module "*.bmp" {
const src: string;
export default src;
}
-declare module '*.gif' {
+declare module "*.gif" {
const src: string;
export default src;
}
-declare module '*.jpg' {
+declare module "*.jpg" {
const src: string;
export default src;
}
-declare module '*.jpeg' {
+declare module "*.jpeg" {
const src: string;
export default src;
}
-declare module '*.png' {
+declare module "*.png" {
const src: string;
export default src;
}
-declare module '*.webp' {
+declare module "*.webp" {
const src: string;
export default src;
}
-declare module '*.svg' {
- import * as React from 'react';
+declare module "*.svg" {
+ import * as React from "react";
export const ReactComponent: React.FunctionComponent<React.SVGProps<
SVGSVGElement
@@ -50,17 +50,17 @@ declare module '*.svg' {
export default src;
}
-declare module '*.module.css' {
+declare module "*.module.css" {
const classes: { readonly [key: string]: string };
export default classes;
}
-declare module '*.module.scss' {
+declare module "*.module.scss" {
const classes: { readonly [key: string]: string };
export default classes;
}
-declare module '*.module.sass' {
+declare module "*.module.sass" {
const classes: { readonly [key: string]: string };
export default classes;
}
diff --git a/src/serviceWorker.ts b/src/serviceWorker.ts
index 2b4d2b5..600d89d 100644
--- a/src/serviceWorker.ts
+++ b/src/serviceWorker.ts
@@ -1,10 +1,10 @@
const isLocalhost = Boolean(
- window.location.hostname === 'localhost' ||
+ window.location.hostname === "localhost" ||
// [::1] is the IPv6 localhost address.
- window.location.hostname === '[::1]' ||
+ window.location.hostname === "[::1]" ||
// 127.0.0.0/8 are considered localhost for IPv4.
window.location.hostname.match(
- /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
+ /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
@@ -13,125 +13,125 @@ type Config = {
onUpdate?: (registration: ServiceWorkerRegistration) => void;
};
-export function register(config?: Config) {
- if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
+export function register(config?: Config): void {
+ if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) {
// The URL constructor is available in all browsers that support SW.
- const publicUrl = new URL(
- process.env.PUBLIC_URL,
- window.location.href
- );
- if (publicUrl.origin !== window.location.origin) {
- // Our service worker won't work if PUBLIC_URL is on a different origin
- // from what our page is served on. This might happen if a CDN is used to
- // serve assets; see https://github.com/facebook/create-react-app/issues/2374
- return;
- }
+ const publicUrl = new URL(
+ process.env.PUBLIC_URL,
+ window.location.href
+ );
+ if (publicUrl.origin !== window.location.origin) {
+ // Our service worker won't work if PUBLIC_URL is on a different origin
+ // from what our page is served on. This might happen if a CDN is used to
+ // serve assets; see https://github.com/facebook/create-react-app/issues/2374
+ return;
+ }
- window.addEventListener('load', () => {
- const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
+ window.addEventListener("load", () => {
+ const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
- if (isLocalhost) {
- // This is running on localhost. Let's check if a service worker still exists or not.
- checkValidServiceWorker(swUrl, config);
+ if (isLocalhost) {
+ // This is running on localhost. Let's check if a service worker still exists or not.
+ checkValidServiceWorker(swUrl, config);
- // Add some additional logging to localhost, pointing developers to the
- // service worker/PWA documentation.
- navigator.serviceWorker.ready.then(() => {
- console.log(
- 'This web app is being served cache-first by a service ' +
- 'worker. To learn more, visit https://bit.ly/CRA-PWA'
- );
+ // Add some additional logging to localhost, pointing developers to the
+ // service worker/PWA documentation.
+ navigator.serviceWorker.ready.then(() => {
+ console.log(
+ "This web app is being served cache-first by a service " +
+ "worker. To learn more, visit https://bit.ly/CRA-PWA"
+ );
+ });
+ } else {
+ // Is not localhost. Just register service worker
+ registerValidSW(swUrl, config);
+ }
});
- } else {
- // Is not localhost. Just register service worker
- registerValidSW(swUrl, config);
- }
- });
- }
+ }
}
function registerValidSW(swUrl: string, config?: Config) {
- navigator.serviceWorker
- .register(swUrl)
- .then(registration => {
- registration.onupdatefound = () => {
- const installingWorker = registration.installing;
- if (installingWorker == null) {
- return;
- }
- installingWorker.onstatechange = () => {
- if (installingWorker.state === 'installed') {
- if (navigator.serviceWorker.controller) {
- // At this point, the updated precached content has been fetched,
- // but the previous service worker will still serve the older
- // content until all client tabs are closed.
- console.log(
- 'New content is available and will be used when all ' +
- 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
- );
+ navigator.serviceWorker
+ .register(swUrl)
+ .then(registration => {
+ registration.onupdatefound = () => {
+ const installingWorker = registration.installing;
+ if (installingWorker == null) {
+ return;
+ }
+ installingWorker.onstatechange = () => {
+ if (installingWorker.state === "installed") {
+ if (navigator.serviceWorker.controller) {
+ // At this point, the updated precached content has been fetched,
+ // but the previous service worker will still serve the older
+ // content until all client tabs are closed.
+ console.log(
+ "New content is available and will be used when all " +
+ "tabs for this page are closed. See https://bit.ly/CRA-PWA."
+ );
- // Execute callback
- if (config && config.onUpdate) {
- config.onUpdate(registration);
- }
- } else {
- // At this point, everything has been precached.
- // It's the perfect time to display a
- // "Content is cached for offline use." message.
- console.log('Content is cached for offline use.');
+ // Execute callback
+ if (config && config.onUpdate) {
+ config.onUpdate(registration);
+ }
+ } else {
+ // At this point, everything has been precached.
+ // It's the perfect time to display a
+ // "Content is cached for offline use." message.
+ console.log("Content is cached for offline use.");
- // Execute callback
- if (config && config.onSuccess) {
- config.onSuccess(registration);
- }
- }
- }
- };
- };
- })
- .catch(error => {
- console.error('Error during service worker registration:', error);
- });
+ // Execute callback
+ if (config && config.onSuccess) {
+ config.onSuccess(registration);
+ }
+ }
+ }
+ };
+ };
+ })
+ .catch(error => {
+ console.error("Error during service worker registration:", error);
+ });
}
function checkValidServiceWorker(swUrl: string, config?: Config) {
- // Check if the service worker can be found. If it can't reload the page.
- fetch(swUrl, {
- headers: { 'Service-Worker': 'script' }
- })
- .then(response => {
- // Ensure service worker exists, and that we really are getting a JS file.
- const contentType = response.headers.get('content-type');
- if (
- response.status === 404 ||
- (contentType != null && contentType.indexOf('javascript') === -1)
- ) {
- // No service worker found. Probably a different app. Reload the page.
- navigator.serviceWorker.ready.then(registration => {
- registration.unregister().then(() => {
- window.location.reload();
- });
- });
- } else {
- // Service worker found. Proceed as normal.
- registerValidSW(swUrl, config);
- }
+ // Check if the service worker can be found. If it can't reload the page.
+ fetch(swUrl, {
+ headers: { "Service-Worker": "script" }
})
- .catch(() => {
- console.log(
- 'No internet connection found. App is running in offline mode.'
- );
- });
+ .then(response => {
+ // Ensure service worker exists, and that we really are getting a JS file.
+ const contentType = response.headers.get("content-type");
+ if (
+ response.status === 404 ||
+ (contentType != null && contentType.indexOf("javascript") === -1)
+ ) {
+ // No service worker found. Probably a different app. Reload the page.
+ navigator.serviceWorker.ready.then(registration => {
+ registration.unregister().then(() => {
+ window.location.reload();
+ });
+ });
+ } else {
+ // Service worker found. Proceed as normal.
+ registerValidSW(swUrl, config);
+ }
+ })
+ .catch(() => {
+ console.log(
+ "No internet connection found. App is running in offline mode."
+ );
+ });
}
-export function unregister() {
- if ('serviceWorker' in navigator) {
- navigator.serviceWorker.ready
- .then(registration => {
- registration.unregister();
- })
- .catch(error => {
- console.error(error.message);
- });
- }
+export function unregister(): void {
+ if ("serviceWorker" in navigator) {
+ navigator.serviceWorker.ready
+ .then(registration => {
+ registration.unregister();
+ })
+ .catch(error => {
+ console.error(error.message);
+ });
+ }
}
diff --git a/src/setupTests.ts b/src/setupTests.ts
index 4dc2c73..5018a42 100644
--- a/src/setupTests.ts
+++ b/src/setupTests.ts
@@ -1,2 +1,2 @@
-import '@testing-library/jest-dom/extend-expect';
+import "@testing-library/jest-dom/extend-expect";
diff --git a/src/tests/App.test.tsx b/src/tests/App.test.tsx
index e050d4f..4765f87 100644
--- a/src/tests/App.test.tsx
+++ b/src/tests/App.test.tsx
@@ -1,9 +1,9 @@
-import React from 'react';
-import { render } from '@testing-library/react';
+import React from "react";
+import { render } from "@testing-library/react";
import App from "../App";
-test('renders app to body', () => {
+test("renders app to body", () => {
const { container } = render(<App />);
expect(container).toBeInTheDocument();
});
diff --git a/src/tests/api/forms.test.ts b/src/tests/api/forms.test.ts
index 6e63965..10ccaa3 100644
--- a/src/tests/api/forms.test.ts
+++ b/src/tests/api/forms.test.ts
@@ -1,7 +1,7 @@
-import { getForm, getForms } from "../../api/forms";
+import { getForm } from "../../api/forms";
-test('fetch a specific form', () => {
- expect(getForm("ban-appeals")).resolves.toHaveProperty("name", "Ban Appeals")
+test("fetch a specific form", () => {
+ 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 0afe10c..ad76381 100644
--- a/src/tests/components/FormListing.test.tsx
+++ b/src/tests/components/FormListing.test.tsx
@@ -1,11 +1,11 @@
-import React from 'react';
-import { render } from '@testing-library/react';
-import '@testing-library/jest-dom/extend-expect';
+import React from "react";
+import { render } from "@testing-library/react";
+import "@testing-library/jest-dom/extend-expect";
import FormListing from "../../components/FormListing";
-import { BrowserRouter as Router } from 'react-router-dom';
-import { Form, FormFeatures } from '../../api/forms';
-import { QuestionType } from '../../api/question';
+import { BrowserRouter as Router } from "react-router-dom";
+import { Form, FormFeatures } from "../../api/forms";
+import { QuestionType } from "../../api/question";
const openFormListing: Form = {
name: "Example form listing",
@@ -20,7 +20,7 @@ const openFormListing: Form = {
"data": {}
}
]
-}
+};
const closedFormListing: Form = {
name: "Example form listing",
@@ -35,28 +35,28 @@ const closedFormListing: Form = {
"data": {}
}
]
-}
+};
-test('renders form listing with specified title', () => {
+test("renders form listing with specified title", () => {
const { getByText } = render(<Router><FormListing form={openFormListing} /></Router>);
const formListing = getByText(/Example form listing/i);
expect(formListing).toBeInTheDocument();
});
-test('renders form listing with specified description', () => {
+test("renders form listing with specified description", () => {
const { getByText } = render(<Router><FormListing form={openFormListing} /></Router>);
const formListing = getByText(/My form listing/i);
expect(formListing).toBeInTheDocument();
});
-test('renders form listing with background green colour for open', () => {
+test("renders form listing with background green colour for open", () => {
const { container } = render(<Router><FormListing form={openFormListing} /></Router>);
const elem = container.querySelector("a");
const style = window.getComputedStyle(elem);
expect(style.backgroundColor).toBe("rgb(67, 181, 129)");
});
-test('renders form listing with background dark colour for closed', () => {
+test("renders form listing with background dark colour for closed", () => {
const { container } = render(<Router><FormListing form={closedFormListing} /></Router>);
const elem = container.querySelector("a");
const style = window.getComputedStyle(elem);
diff --git a/src/tests/components/HeaderBar.test.tsx b/src/tests/components/HeaderBar.test.tsx
index 6963859..9c232ad 100644
--- a/src/tests/components/HeaderBar.test.tsx
+++ b/src/tests/components/HeaderBar.test.tsx
@@ -1,15 +1,15 @@
-import React from 'react';
-import { render } from '@testing-library/react';
-import '@testing-library/jest-dom/extend-expect'
+import React from "react";
+import { render } from "@testing-library/react";
+import "@testing-library/jest-dom/extend-expect";
import HeaderBar from "../../components/HeaderBar";
-test('renders header bar with title', () => {
+test("renders header bar with title", () => {
const { getByText } = render(<HeaderBar />);
const formListing = getByText(/Python Discord Forms/i);
expect(formListing).toBeInTheDocument();
});
-test('renders header bar with custom title', () => {
+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/src/tests/components/OAuth2Button.test.tsx b/src/tests/components/OAuth2Button.test.tsx
index 53875dc..f05159f 100644
--- a/src/tests/components/OAuth2Button.test.tsx
+++ b/src/tests/components/OAuth2Button.test.tsx
@@ -1,8 +1,8 @@
-import React from 'react';
-import { render } from '@testing-library/react';
+import React from "react";
+import { render } from "@testing-library/react";
import OAuth2Button from "../../components/OAuth2Button";
-test('renders oauth2 sign in button text', () => {
+test("renders oauth2 sign in button text", () => {
const { getByText } = render(<OAuth2Button />);
const button = getByText(/Sign in with Discord/i);
expect(button).toBeInTheDocument();
@@ -10,6 +10,6 @@ test('renders oauth2 sign in button text', () => {
test("renders fontawesome discord icon", () => {
const { container } = render(<OAuth2Button/>);
- const icon = container.querySelector(`[data-icon="discord"]`)
+ const icon = container.querySelector("[data-icon=\"discord\"]");
expect(icon).toBeInTheDocument();
-})
+});
diff --git a/src/tests/components/Tag.test.tsx b/src/tests/components/Tag.test.tsx
index 67f2a85..50b3b0e 100644
--- a/src/tests/components/Tag.test.tsx
+++ b/src/tests/components/Tag.test.tsx
@@ -1,28 +1,28 @@
-import React from 'react';
-import { render } from '@testing-library/react';
+import React from "react";
+import { render } from "@testing-library/react";
import Tag from "../../components/Tag";
-test('renders tag with specified text', () => {
+test("renders tag with specified text", () => {
const { getByText } = render(<Tag text="Test" color="#f0f0f0" />);
const tag = getByText(/Test/i);
expect(tag).toBeInTheDocument();
});
-test('renders tag with specified color', () => {
+test("renders tag with specified color", () => {
const { getByText } = render(<Tag text="Test" color="#f0f0f0" />);
const tag = getByText(/Test/i);
const style = window.getComputedStyle(tag);
expect(style.backgroundColor).toBe("rgb(240, 240, 240)");
});
-test('renders tag with specified font size', () => {
+test("renders tag with specified font size", () => {
const { getByText } = render(<Tag text="Test" color="#f0f0f0" fontSize="2em" />);
const tag = getByText(/Test/i);
const style = window.getComputedStyle(tag);
expect(style.fontSize).toBe("2em");
});
-test('defaults to 0.75em when no tag font size is passed', () => {
+test("defaults to 0.75em when no tag font size is passed", () => {
const { getByText } = render(<Tag text="Test" color="#f0f0f0" />);
const tag = getByText(/Test/i);
const style = window.getComputedStyle(tag);
diff --git a/src/tests/globalStyles.test.ts b/src/tests/globalStyles.test.ts
index d44cc51..a7017c8 100644
--- a/src/tests/globalStyles.test.ts
+++ b/src/tests/globalStyles.test.ts
@@ -2,4 +2,4 @@ import globalStyles from "../globalStyles";
test("global styles emotion css compiles", () => {
expect(globalStyles.styles).not.toBeUndefined();
-})
+});
diff --git a/src/tests/pages/CallbackPage.test.tsx b/src/tests/pages/CallbackPage.test.tsx
index e878577..9049ca3 100644
--- a/src/tests/pages/CallbackPage.test.tsx
+++ b/src/tests/pages/CallbackPage.test.tsx
@@ -1,23 +1,23 @@
-import React from 'react';
-import { render } from '@testing-library/react';
+import React from "react";
+import { render } from "@testing-library/react";
-import CallbackPage from '../../pages/CallbackPage';
+import CallbackPage from "../../pages/CallbackPage";
-test('callback page renders provided code', () => {
+test("callback page renders provided code", () => {
global.opener = {
postMessage: jest.fn()
- }
+ };
- let mockLocation = new URL("https://forms.pythondiscord.com/authorize?code=abcdef");
+ const mockLocation = new URL("https://forms.pythondiscord.com/authorize?code=abcdef");
- Object.defineProperty(global, "location", {value: mockLocation})
+ Object.defineProperty(global, "location", {value: mockLocation});
- let comp = <CallbackPage />;
+ const comp = <CallbackPage />;
const { getByText } = render(comp);
- let codeText = getByText(/Code is abcdef/);
+ const codeText = getByText(/Code is abcdef/);
expect(codeText).toBeInTheDocument();
- expect(global.opener.postMessage).toBeCalledTimes(1)
+ expect(global.opener.postMessage).toBeCalledTimes(1);
});
diff --git a/src/tests/pages/FormPage.test.tsx b/src/tests/pages/FormPage.test.tsx
index 7bfc763..f7ecc32 100644
--- a/src/tests/pages/FormPage.test.tsx
+++ b/src/tests/pages/FormPage.test.tsx
@@ -1,28 +1,28 @@
-import React from 'react';
-import { render } from '@testing-library/react';
+import React from "react";
+import { render } from "@testing-library/react";
import { createMemoryHistory } from "history";
import { Route, BrowserRouter as Router } from "react-router-dom";
-import FormPage from '../../pages/FormPage';
+import FormPage from "../../pages/FormPage";
import * as forms from "../../api/forms";
-test('renders specific form page with loading bar', () => {
+test("renders specific form page with loading bar", () => {
const history = createMemoryHistory();
history.push("/form/route");
const { getByText } = render(<Router><Route history={history} ><FormPage /></Route></Router>);
// If we rendered the headerbar we rendered the forms page.
- let headerBar = getByText(/Loading.../);
+ const headerBar = getByText(/Loading.../);
expect(headerBar).toBeInTheDocument();
});
-test('calls api method to load form', () => {
+test("calls api method to load form", () => {
const history = createMemoryHistory();
history.push("/form/ban-appeals");
- let oldImpl = forms.getForm;
+ const oldImpl = forms.getForm;
Object.defineProperty(forms, "getForm", {value: jest.fn(oldImpl)});
diff --git a/src/tests/pages/LandingPage.test.tsx b/src/tests/pages/LandingPage.test.tsx
index 23195bd..5635e63 100644
--- a/src/tests/pages/LandingPage.test.tsx
+++ b/src/tests/pages/LandingPage.test.tsx
@@ -1,11 +1,11 @@
-import React from 'react';
-import { render } from '@testing-library/react';
+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';
+import { QuestionType } from "../../api/question";
const testingForm: forms.Form = {
"id": "testing-form",
@@ -20,15 +20,15 @@ const testingForm: forms.Form = {
"data": {}
}
]
-}
+};
-test('renders landing page', () => {
+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]);
+ handleForms.mockImplementation(() => [[testingForm], setForms]);
const { getByText } = render(<Router><LandingPage /></Router>);
// If we rendered the headerbar we rendered the landing page.
- let headerBar = getByText(/Python Discord Forms/);
+ const headerBar = getByText(/Python Discord Forms/);
expect(headerBar).toBeInTheDocument();
});