Skip to content

Commit

Permalink
global-error-handling
Browse files Browse the repository at this point in the history
  • Loading branch information
benawad committed Aug 12, 2020
1 parent df68f94 commit b14dd1d
Show file tree
Hide file tree
Showing 10 changed files with 172 additions and 14 deletions.
9 changes: 8 additions & 1 deletion web/src/components/InputField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,33 @@ import {
FormLabel,
Input,
FormErrorMessage,
Textarea,
} from "@chakra-ui/core";

type InputFieldProps = InputHTMLAttributes<HTMLInputElement> & {
label: string;
name: string;
textarea?: boolean;
};

// '' => false
// 'error message stuff' => true

export const InputField: React.FC<InputFieldProps> = ({
label,
textarea,
size: _,
...props
}) => {
let InputOrTextarea = Input;
if (textarea) {
InputOrTextarea = Textarea;
}
const [field, { error }] = useField(props);
return (
<FormControl isInvalid={!!error}>
<FormLabel htmlFor={field.name}>{label}</FormLabel>
<Input {...field} {...props} id={field.name} />
<InputOrTextarea {...field} {...props} id={field.name} />
{error ? <FormErrorMessage>{error}</FormErrorMessage> : null}
</FormControl>
);
Expand Down
16 changes: 16 additions & 0 deletions web/src/components/Layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from "react";
import { Wrapper, WrapperVariant } from "./Wrapper";
import { NavBar } from "./NavBar";

interface LayoutProps {
variant?: WrapperVariant;
}

export const Layout: React.FC<LayoutProps> = ({ children, variant }) => {
return (
<>
<NavBar />
<Wrapper variant={variant}>{children}</Wrapper>
</>
);
};
2 changes: 1 addition & 1 deletion web/src/components/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const NavBar: React.FC<NavBarProps> = ({}) => {
}

return (
<Flex bg="tan" p={4}>
<Flex zIndex={1} position="sticky" top={0} bg="tan" p={4}>
<Box ml={"auto"}>{body}</Box>
</Flex>
);
Expand Down
4 changes: 3 additions & 1 deletion web/src/components/Wrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import React from "react";
import { Box } from "@chakra-ui/core";

export type WrapperVariant = "small" | "regular";

interface WrapperProps {
variant?: "small" | "regular";
variant?: WrapperVariant;
}

export const Wrapper: React.FC<WrapperProps> = ({
Expand Down
46 changes: 42 additions & 4 deletions web/src/generated/graphql.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,21 @@ export type QueryPostArgs = {
export type Post = {
__typename?: 'Post';
id: Scalars['Float'];
title: Scalars['String'];
text: Scalars['String'];
points: Scalars['Float'];
creatorId: Scalars['Float'];
createdAt: Scalars['String'];
updatedAt: Scalars['String'];
title: Scalars['String'];
};

export type User = {
__typename?: 'User';
id: Scalars['Float'];
createdAt: Scalars['String'];
updatedAt: Scalars['String'];
username: Scalars['String'];
email: Scalars['String'];
createdAt: Scalars['String'];
updatedAt: Scalars['String'];
};

export type Mutation = {
Expand All @@ -56,7 +59,7 @@ export type Mutation = {


export type MutationCreatePostArgs = {
title: Scalars['String'];
input: PostInput;
};


Expand Down Expand Up @@ -92,6 +95,11 @@ export type MutationLoginArgs = {
usernameOrEmail: Scalars['String'];
};

export type PostInput = {
title: Scalars['String'];
text: Scalars['String'];
};

export type UserResponse = {
__typename?: 'UserResponse';
errors?: Maybe<Array<FieldError>>;
Expand Down Expand Up @@ -145,6 +153,19 @@ export type ChangePasswordMutation = (
) }
);

export type CreatePostMutationVariables = Exact<{
input: PostInput;
}>;


export type CreatePostMutation = (
{ __typename?: 'Mutation' }
& { createPost: (
{ __typename?: 'Post' }
& Pick<Post, 'id' | 'createdAt' | 'updatedAt' | 'title' | 'text' | 'points' | 'creatorId'>
) }
);

export type ForgotPasswordMutationVariables = Exact<{
email: Scalars['String'];
}>;
Expand Down Expand Up @@ -246,6 +267,23 @@ export const ChangePasswordDocument = gql`
export function useChangePasswordMutation() {
return Urql.useMutation<ChangePasswordMutation, ChangePasswordMutationVariables>(ChangePasswordDocument);
};
export const CreatePostDocument = gql`
mutation CreatePost($input: PostInput!) {
createPost(input: $input) {
id
createdAt
updatedAt
title
text
points
creatorId
}
}
`;

export function useCreatePostMutation() {
return Urql.useMutation<CreatePostMutation, CreatePostMutationVariables>(CreatePostDocument);
};
export const ForgotPasswordDocument = gql`
mutation ForgotPassword($email: String!) {
forgotPassword(email: $email)
Expand Down
11 changes: 11 additions & 0 deletions web/src/graphql/mutations/createPost.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
mutation CreatePost($input: PostInput!) {
createPost(input: $input) {
id
createdAt
updatedAt
title
text
points
creatorId
}
}
53 changes: 53 additions & 0 deletions web/src/pages/create-post.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Box, Button } from "@chakra-ui/core";
import { Form, Formik } from "formik";
import { withUrqlClient } from "next-urql";
import { useRouter } from "next/router";
import React from "react";
import { InputField } from "../components/InputField";
import { Layout } from "../components/Layout";
import { useCreatePostMutation } from "../generated/graphql";
import { createUrqlClient } from "../utils/createUrqlClient";
import { useIsAuth } from "../utils/useIsAuth";

const CreatePost: React.FC<{}> = ({}) => {
const router = useRouter();
useIsAuth();
const [, createPost] = useCreatePostMutation();
return (
<Layout variant="small">
<Formik
initialValues={{ title: "", text: "" }}
onSubmit={async (values) => {
const { error } = await createPost({ input: values });
if (!error) {
router.push("/");
}
}}
>
{({ isSubmitting }) => (
<Form>
<InputField name="title" placeholder="title" label="Title" />
<Box mt={4}>
<InputField
textarea
name="text"
placeholder="text..."
label="Body"
/>
</Box>
<Button
mt={4}
type="submit"
isLoading={isSubmitting}
variantColor="teal"
>
create post
</Button>
</Form>
)}
</Formik>
</Layout>
);
};

export default withUrqlClient(createUrqlClient)(CreatePost);
12 changes: 8 additions & 4 deletions web/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,24 @@ import { NavBar } from "../components/NavBar";
import { withUrqlClient } from "next-urql";
import { createUrqlClient } from "../utils/createUrqlClient";
import { usePostsQuery } from "../generated/graphql";
import { Layout } from "../components/Layout";
import { Link } from "@chakra-ui/core";
import NextLink from "next/link";

const Index = () => {
const [{ data }] = usePostsQuery();
return (
<>
<NavBar />
<div>hello world</div>
<Layout>
<NextLink href="/create-post">
<Link>create post</Link>
</NextLink>
<br />
{!data ? (
<div>loading...</div>
) : (
data.posts.map((p) => <div key={p.id}>{p.title}</div>)
)}
</>
</Layout>
);
};

Expand Down
20 changes: 17 additions & 3 deletions web/src/utils/createUrqlClient.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
import { dedupExchange, fetchExchange } from "urql";
import { cacheExchange } from "@urql/exchange-graphcache";
import { dedupExchange, Exchange, fetchExchange } from "urql";
import { pipe, tap } from "wonka";
import {
LoginMutation,
LogoutMutation,
MeQuery,
MeDocument,
LoginMutation,
MeQuery,
RegisterMutation,
} from "../generated/graphql";
import { betterUpdateQuery } from "./betterUpdateQuery";
import Router from "next/router";

const errorExchange: Exchange = ({ forward }) => (ops$) => {
return pipe(
forward(ops$),
tap(({ error }) => {
if (error?.message.includes("not authenticated")) {
Router.replace("/login");
}
})
);
};

export const createUrqlClient = (ssrExchange: any) => ({
url: "http://localhost:4000/graphql",
Expand Down Expand Up @@ -62,6 +75,7 @@ export const createUrqlClient = (ssrExchange: any) => ({
},
},
}),
errorExchange,
ssrExchange,
fetchExchange,
],
Expand Down
13 changes: 13 additions & 0 deletions web/src/utils/useIsAuth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { useMeQuery } from "../generated/graphql";
import { useRouter } from "next/router";
import { useEffect } from "react";

export const useIsAuth = () => {
const [{ data, fetching }] = useMeQuery();
const router = useRouter();
useEffect(() => {
if (!fetching && !data?.me) {
router.replace("/login");
}
}, [fetching, data, router]);
};

0 comments on commit b14dd1d

Please sign in to comment.