Skip to content

Commit

Permalink
feat: adds feeds as a sample for CRUD
Browse files Browse the repository at this point in the history
  • Loading branch information
ghoshnirmalya committed Aug 1, 2020
1 parent 39b07ac commit 4099cea
Show file tree
Hide file tree
Showing 16 changed files with 466 additions and 225 deletions.
40 changes: 40 additions & 0 deletions backend/metadata/tables.yaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,52 @@
- table:
schema: public
name: accounts
- table:
schema: public
name: feeds
object_relationships:
- name: author
using:
manual_configuration:
remote_table:
schema: public
name: users
column_mapping:
author_id: id
insert_permissions:
- role: user
permission:
check:
author_id:
_eq: X-Hasura-User-Id
columns:
- body
backend_only: false
select_permissions:
- role: user
permission:
columns:
- body
- created_at
- updated_at
- author_id
- id
filter: {}
- table:
schema: public
name: sessions
- table:
schema: public
name: users
array_relationships:
- name: feeds
using:
manual_configuration:
remote_table:
schema: public
name: feeds
column_mapping:
id: author_id
insert_permissions:
- role: user
permission:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE "public"."feeds";
18 changes: 18 additions & 0 deletions backend/migrations/1596135561298_create_table_public_feeds/up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE TABLE "public"."feeds"("id" uuid NOT NULL DEFAULT gen_random_uuid(), "author_id" uuid NOT NULL, "body" text NOT NULL, "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), PRIMARY KEY ("id") );
CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"()
RETURNS TRIGGER AS $$
DECLARE
_new record;
BEGIN
_new := NEW;
_new."updated_at" = NOW();
RETURN _new;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER "set_public_feeds_updated_at"
BEFORE UPDATE ON "public"."feeds"
FOR EACH ROW
EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"();
COMMENT ON TRIGGER "set_public_feeds_updated_at" ON "public"."feeds"
IS 'trigger to set value of column "updated_at" to current timestamp on row update';
9 changes: 9 additions & 0 deletions backend/seeds/1596139319243_tables_seed.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
INSERT INTO public.accounts (id, compound_id, user_id, provider_type, provider_id, provider_account_id, refresh_token, access_token, access_token_expires, created_at, updated_at) VALUES ('4a250393-1aa8-4fbc-a349-672609d7ce79', '758a69951dd3f2a6b93662db4c55b22f2333216c5c2079ddf95f557185696af8', '72ad01dc-9c5e-4844-a60d-6b653c75a363', 'oauth', 'google', '110127495875220400815', NULL, 'ya29.a0AfH6SMCyjCqi1qMu1dqQu0DWDJ-DUketNL7oRrJklZdl67lgUPSLj3sqb7Wil72G9IBCY5L3iSipakAOtPyvDu1Vbu9eCSYmmjitLoKtbBIpdl2Ypfg4_8NDmGgWfl-sJJbyNn7RKMEn4x1wF8U5YpMiA5fn3ZVVrd9f', NULL, '2020-07-30 15:38:05.270128+00', '2020-07-30 15:38:05.270128+00');
INSERT INTO public.feeds (id, author_id, body, created_at, updated_at) VALUES ('bfa5a42d-1fe9-4fd7-a47c-6bc6e074fc51', '72ad01dc-9c5e-4844-a60d-6b653c75a363', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque pulvinar urna odio, eget fringilla ipsum volutpat ut. Mauris vel nunc ligula. Curabitur neque odio, varius sit amet fringilla eget, maximus sed ante.', '2020-07-30 19:00:44.107312+00', '2020-07-30 19:00:44.107312+00');
INSERT INTO public.feeds (id, author_id, body, created_at, updated_at) VALUES ('07b160d8-8cf3-48be-8bef-aa73f6e459c4', '72ad01dc-9c5e-4844-a60d-6b653c75a363', 'Morbi mollis tristique tempus. Cras finibus tristique velit, dignissim porttitor enim euismod eu. Duis tincidunt lacinia interdum. Sed eu elit mollis, condimentum nisl iaculis, convallis tortor.', '2020-07-30 19:38:50.639452+00', '2020-07-30 19:38:50.639452+00');
INSERT INTO public.feeds (id, author_id, body, created_at, updated_at) VALUES ('15364138-6591-413f-b6db-7dd34e354c45', '72ad01dc-9c5e-4844-a60d-6b653c75a363', 'Nam condimentum posuere eleifend. Proin rhoncus mi in mi congue, et varius velit semper. Integer suscipit sed augue a interdum. Nunc dictum vulputate facilisis. ', '2020-07-30 19:47:30.427743+00', '2020-07-30 19:47:30.427743+00');
INSERT INTO public.feeds (id, author_id, body, created_at, updated_at) VALUES ('8ae90763-9746-4a0c-b952-71c9bda6cab8', '72ad01dc-9c5e-4844-a60d-6b653c75a363', 'Nulla tempor in leo ut ultrices. Integer eget est at massa ultrices lobortis in ac nisi. Sed lacinia odio ut felis mattis bibendum.', '2020-07-30 19:50:28.129349+00', '2020-07-30 19:50:28.129349+00');
INSERT INTO public.feeds (id, author_id, body, created_at, updated_at) VALUES ('6e2b67cb-d8cf-4d9b-842b-2e731dd040cd', '72ad01dc-9c5e-4844-a60d-6b653c75a363', 'Nunc bibendum viverra nisi, vel sollicitudin urna malesuada sed. Nunc vehicula augue et massa sodales, ac euismod ante varius. Mauris at pretium orci. Pellentesque rutrum a enim et mollis. In metus risus, elementum in felis consectetur, eleifend ultricies leo. Maecenas interdum convallis mauris, eget lobortis ex accumsan et. Aliquam tristique sem id velit pellentesque suscipit.', '2020-07-30 19:52:21.535422+00', '2020-07-30 19:52:21.535422+00');
INSERT INTO public.feeds (id, author_id, body, created_at, updated_at) VALUES ('e3df2e9a-17c5-4c35-ad65-609b480f3d04', '72ad01dc-9c5e-4844-a60d-6b653c75a363', 'Curabitur vel vestibulum magna. Curabitur et arcu quis ligula lacinia mattis at facilisis orci. Vivamus ac elit nunc. Mauris magna turpis, laoreet quis pharetra eget, vulputate non nisi. Nullam condimentum volutpat sapien vel mattis. Donec nibh ex, tempor id felis quis, varius euismod augue.', '2020-07-30 19:52:32.01556+00', '2020-07-30 19:52:32.01556+00');
INSERT INTO public.feeds (id, author_id, body, created_at, updated_at) VALUES ('91da0b4a-9a82-4d75-b03b-2f306606fa00', '72ad01dc-9c5e-4844-a60d-6b653c75a363', 'Duis facilisis orci sed nisi luctus, vitae pretium neque malesuada. Nullam posuere pharetra lacinia. Maecenas vel leo nisl.', '2020-07-30 19:53:11.154018+00', '2020-07-30 19:53:11.154018+00');
INSERT INTO public.users (id, name, email, email_verified, image, created_at, updated_at) VALUES ('72ad01dc-9c5e-4844-a60d-6b653c75a363', 'John Doe', 'john@doe.com', NULL, '', '2020-07-30 15:38:05.240549+00', '2020-07-30 19:40:53.634539+00');
5 changes: 0 additions & 5 deletions backend/seeds/1596186182039_tables_seed.sql

This file was deleted.

15 changes: 4 additions & 11 deletions frontend/components/navbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
Stack,
Link as _Link,
Button,
Switch,
IconButton,
useColorMode,
} from "@chakra-ui/core";
Expand All @@ -16,7 +15,6 @@ const Navbar: NextComponentType = () => {
const [session] = useSession();
const { colorMode, toggleColorMode } = useColorMode();
const bgColor = { light: "white", dark: "gray.800" };
const borderColor = { light: "gray.300", dark: "gray.700" };
const color = { light: "gray.800", dark: "gray.100" };

const handleToggleTheme = () => {
Expand All @@ -35,9 +33,9 @@ const Navbar: NextComponentType = () => {

const linksForAuthenticatedUsers = [
{
id: "users",
label: "Users",
href: "/users",
id: "feeds",
label: "Feeds",
href: "/feeds",
},
{
id: "myAccount",
Expand Down Expand Up @@ -103,12 +101,7 @@ const Navbar: NextComponentType = () => {

return (
<Box bg={bgColor[colorMode]}>
<Box
p={4}
color={color[colorMode]}
borderWidth={1}
borderColor={borderColor[colorMode]}
>
<Box p={4} color={color[colorMode]} shadow="lg" pos="relative">
<Box maxW="6xl" mx="auto" w="full">
<Stack
isInline
Expand Down
108 changes: 108 additions & 0 deletions frontend/components/pages/feeds/add-new-feed-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import React, { useState, FormEvent } from "react";
import gql from "graphql-tag";
import { useMutation } from "urql";
import {
Box,
Stack,
FormControl,
FormLabel,
Button,
Alert,
AlertIcon,
AlertTitle,
CloseButton,
Textarea,
useColorMode,
} from "@chakra-ui/core";
import { useSession } from "next-auth/client";
import AccessDeniedIndicator from "components/access-denied-indicator";

const insertFeedMutation = gql`
mutation insertFeed($userId: uuid!, $body: String) {
insert_feeds_one(object: { author_id: $userId, body: $body }) {
id
}
}
`;

const AddNewFeedForm = () => {
const { colorMode } = useColorMode();
const bgColor = { light: "white", dark: "gray.800" };
const color = { light: "gray.800", dark: "gray.100" };
const [body, setBody] = useState("");
const [session] = useSession();

if (!session) {
return (
<AccessDeniedIndicator message="You need to be signed in to add a new feed!" />
);
}

const [
{ fetching: insertFeedFetching, error: insertFeedError },
insertFeed,
] = useMutation(insertFeedMutation);

const handleSubmit = async () => {
await insertFeed({
userId: session.id,
body,
});

setBody("");
};

const errorNode = () => {
if (!insertFeedError) {
return false;
}

return (
<Alert status="error">
<AlertIcon />
<AlertTitle>{insertFeedError}</AlertTitle>
<CloseButton position="absolute" right="8px" top="8px" />
</Alert>
);
};

return (
<Stack spacing={4}>
{errorNode()}
<Box
p={4}
bg={bgColor[colorMode]}
color={color[colorMode]}
shadow="lg"
rounded="lg"
>
<Stack spacing={4}>
<FormControl isRequired>
<FormLabel htmlFor="body">What's on your mind?</FormLabel>
<Textarea
id="body"
value={body}
onChange={(e: FormEvent<HTMLInputElement>) =>
setBody(e.currentTarget.value)
}
isDisabled={insertFeedFetching}
/>
</FormControl>
<FormControl>
<Button
variantColor="cyan"
loadingText="Posting..."
onClick={handleSubmit}
isLoading={insertFeedFetching}
isDisabled={!body.trim()}
>
Post
</Button>
</FormControl>
</Stack>
</Box>
</Stack>
);
};

export default AddNewFeedForm;
71 changes: 71 additions & 0 deletions frontend/components/pages/feeds/feed.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React, { FC } from "react";
import {
Box,
Stack,
Text,
Avatar,
useColorMode,
Input,
Button,
} from "@chakra-ui/core";
import IFeed from "types/feed";
import timeFromNow from "lib/time-from-now";

interface IProps {
feed: IFeed;
}

const Feed: FC<IProps> = ({ feed }) => {
const { colorMode } = useColorMode();
const bgColor = { light: "white", dark: "gray.800" };
const color = { light: "gray.800", dark: "gray.100" };
const borderColor = { light: "gray.300", dark: "gray.700" };

const authorNode = () => {
return (
<Stack
spacing={4}
isInline
alignItems="center"
p={4}
borderBottomWidth={1}
borderColor={borderColor[colorMode]}
>
<Avatar name={feed.author.name} src={feed.author.image} />
<Stack>
<Text fontWeight="bold">{feed.author.name}</Text>
<Text>{timeFromNow(feed.created_at)}</Text>
</Stack>
</Stack>
);
};

const bodyNode = () => {
return (
<Text
fontSize="md"
p={4}
borderBottomWidth={1}
borderColor={borderColor[colorMode]}
>
{feed.body}
</Text>
);
};

return (
<Box
bg={bgColor[colorMode]}
color={color[colorMode]}
shadow="lg"
rounded="lg"
>
<Stack spacing={0}>
{authorNode()}
{bodyNode()}
</Stack>
</Box>
);
};

export default Feed;
49 changes: 49 additions & 0 deletions frontend/components/pages/feeds/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from "react";
import gql from "graphql-tag";
import { useSubscription } from "urql";
import { Box, Stack } from "@chakra-ui/core";
import IFeed from "types/feed";
import Feed from "components/pages/feeds/feed";
import AddNewFeedForm from "components/pages/feeds/add-new-feed-form";

const feedsSubscription = gql`
subscription fetchFeeds {
feeds(order_by: { created_at: desc }) {
id
created_at
body
author {
id
name
image
}
}
}
`;

const FeedsPageComponent = () => {
const [result] = useSubscription({
query: feedsSubscription,
});

if (!result.data) {
return <p>No feeds!</p>;
}

return (
<Stack spacing={8}>
<Box>
<AddNewFeedForm />
</Box>
{result.data.feeds.map((feed: IFeed) => {
return (
<Box key={feed.id}>
<Feed feed={feed} />
</Box>
);
})}
</Stack>
);
};

export default FeedsPageComponent;

0 comments on commit 4099cea

Please sign in to comment.