From 329dc81638f0e92a31fa3af07708da806935c3c3 Mon Sep 17 00:00:00 2001 From: Nirmalya Ghosh Date: Sat, 22 Aug 2020 20:45:30 +0530 Subject: [PATCH 1/5] feat: adds authentication using NextAuth --- frontend/.env.example | 4 + .../access-denied-indicator/index.tsx | 42 + frontend/components/layout/container.js | 17 - frontend/components/layout/container.tsx | 23 + .../components/layout/{index.js => index.tsx} | 6 +- frontend/components/loader/index.tsx | 17 + frontend/components/navbar/index.tsx | 148 ++ frontend/components/pages/error/index.tsx | 48 + .../pages/feeds/add-new-feed-form.tsx | 107 ++ .../pages/{index => feeds}/feed.tsx | 8 +- frontend/components/pages/feeds/index.tsx | 49 + frontend/components/pages/index/index.tsx | 106 +- .../components/pages/my-account/index.tsx | 144 ++ frontend/jsconfig.json | 14 - frontend/lib/time-from-now.tsx | 10 + frontend/lib/with-graphql.tsx | 41 +- frontend/package.json | 11 +- frontend/pages/404.tsx | 17 + frontend/pages/_app.tsx | 17 +- frontend/pages/_error.tsx | 27 + frontend/pages/api/auth/[...nextauth].ts | 22 + frontend/pages/feeds.tsx | 36 + frontend/pages/index.tsx | 5 +- frontend/pages/my-account.tsx | 36 + frontend/types/session.ts | 9 + frontend/types/token.ts | 6 + frontend/yarn.lock | 1446 ++++++++++++++++- 27 files changed, 2308 insertions(+), 108 deletions(-) create mode 100644 frontend/components/access-denied-indicator/index.tsx delete mode 100644 frontend/components/layout/container.js create mode 100644 frontend/components/layout/container.tsx rename frontend/components/layout/{index.js => index.tsx} (68%) create mode 100644 frontend/components/loader/index.tsx create mode 100644 frontend/components/navbar/index.tsx create mode 100644 frontend/components/pages/error/index.tsx create mode 100644 frontend/components/pages/feeds/add-new-feed-form.tsx rename frontend/components/pages/{index => feeds}/feed.tsx (77%) create mode 100644 frontend/components/pages/feeds/index.tsx create mode 100644 frontend/components/pages/my-account/index.tsx delete mode 100644 frontend/jsconfig.json create mode 100644 frontend/lib/time-from-now.tsx create mode 100644 frontend/pages/404.tsx create mode 100644 frontend/pages/_error.tsx create mode 100644 frontend/pages/api/auth/[...nextauth].ts create mode 100644 frontend/pages/feeds.tsx create mode 100644 frontend/pages/my-account.tsx create mode 100644 frontend/types/session.ts create mode 100644 frontend/types/token.ts diff --git a/frontend/.env.example b/frontend/.env.example index fd82cf1..d3275f9 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -1 +1,5 @@ NEXT_PUBLIC_API_URL=http://localhost:1337/graphql +NEXTAUTH_URL=http://localhost:3000 +DATABASE_URL=postgres://postgres:@localhost:5432/postgres +GOOGLE_CLIENT_ID="" +GOOGLE_CLIENT_SECRET="" diff --git a/frontend/components/access-denied-indicator/index.tsx b/frontend/components/access-denied-indicator/index.tsx new file mode 100644 index 0000000..736dbd1 --- /dev/null +++ b/frontend/components/access-denied-indicator/index.tsx @@ -0,0 +1,42 @@ +import React, { FC } from "react"; +import { Icon, Flex, Button, Stack, Box } from "@chakra-ui/core"; +import Link from "next/link"; +import { signIn } from "next-auth/client"; + +interface IProps { + message?: string; +} + +const AccessDeniedIndicator: FC = ({ + message = "You need to Sign In to view this content!", +}) => { + const iconNode = () => { + return ; + }; + + const signInButtonNode = () => { + return ( + + + + ); + }; + + return ( + + + {iconNode()} + {signInButtonNode()} + + + ); +}; + +export default AccessDeniedIndicator; diff --git a/frontend/components/layout/container.js b/frontend/components/layout/container.js deleted file mode 100644 index 6ac6bb9..0000000 --- a/frontend/components/layout/container.js +++ /dev/null @@ -1,17 +0,0 @@ -import { Box, useColorMode } from "@chakra-ui/core"; -import React from "react"; - -const Container = ({ children }) => { - const { colorMode } = useColorMode(); - const bgColor = { light: "gray.100", dark: "gray.900" }; - - return ( - - - {children} - - - ); -}; - -export default Container; diff --git a/frontend/components/layout/container.tsx b/frontend/components/layout/container.tsx new file mode 100644 index 0000000..649f879 --- /dev/null +++ b/frontend/components/layout/container.tsx @@ -0,0 +1,23 @@ +import React, { FC } from "react"; +import { Box, useColorMode } from "@chakra-ui/core"; + +const Container: FC = ({ children }) => { + const { colorMode } = useColorMode(); + const bgColor = { light: "gray.100", dark: "gray.900" }; + const heightOfNavbar: string = "74px"; + + return ( + + + {children} + + + ); +}; + +export default Container; diff --git a/frontend/components/layout/index.js b/frontend/components/layout/index.tsx similarity index 68% rename from frontend/components/layout/index.js rename to frontend/components/layout/index.tsx index 8ed7ccb..8eba4ac 100644 --- a/frontend/components/layout/index.js +++ b/frontend/components/layout/index.tsx @@ -1,11 +1,13 @@ +import React, { FC } from "react"; import { ColorModeProvider, LightMode } from "@chakra-ui/core"; import Container from "components/layout/container"; -import React from "react"; +import Navbar from "components/navbar"; -const Layout = ({ children }) => { +const Layout: FC = ({ children }) => { return ( + {children} diff --git a/frontend/components/loader/index.tsx b/frontend/components/loader/index.tsx new file mode 100644 index 0000000..3361e9b --- /dev/null +++ b/frontend/components/loader/index.tsx @@ -0,0 +1,17 @@ +import React, { FC } from "react"; +import { Box, CircularProgress } from "@chakra-ui/core"; + +interface Props { + size?: string; + thickness?: number; +} + +const Loader: FC = ({ size = "50px", thickness = 0.15 }) => { + return ( + + + + ); +}; + +export default Loader; diff --git a/frontend/components/navbar/index.tsx b/frontend/components/navbar/index.tsx new file mode 100644 index 0000000..3487de4 --- /dev/null +++ b/frontend/components/navbar/index.tsx @@ -0,0 +1,148 @@ +import React from "react"; +import { NextComponentType } from "next"; +import Link from "next/link"; +import { signIn, signOut, useSession } from "next-auth/client"; +import { + Box, + Stack, + Link as _Link, + Button, + IconButton, + useColorMode, +} from "@chakra-ui/core"; + +const Navbar: NextComponentType = () => { + const [session] = useSession(); + const { colorMode, toggleColorMode } = useColorMode(); + const bgColor = { light: "white", dark: "gray.800" }; + const color = { light: "gray.800", dark: "gray.100" }; + + const handleToggleTheme = () => { + console.log("hello"); + + toggleColorMode(); + }; + + const linksForAllUsers = [ + { + id: "home", + label: "Home", + href: "/", + }, + ]; + + const linksForAuthenticatedUsers = [ + { + id: "feeds", + label: "Feeds", + href: "/feeds", + }, + { + id: "myAccount", + label: "My Account", + href: "/my-account", + }, + ]; + + const signInButtonNode = () => { + if (session) { + return false; + } + + return ( + + + + + + ); + }; + + const signOutButtonNode = () => { + if (!session) { + return false; + } + + return ( + + + + + + ); + }; + + const themeToggleButtonNode = () => { + return ( + + ); + }; + + return ( + + + + + + + {linksForAllUsers.map((link) => { + return ( + + + <_Link>{link.label} + + + ); + })} + {session && + linksForAuthenticatedUsers.map((link) => { + return ( + + + <_Link>{link.label} + + + ); + })} + + + + + {themeToggleButtonNode()} + {signInButtonNode()} + {signOutButtonNode()} + + + + + + + ); +}; + +export default Navbar; diff --git a/frontend/components/pages/error/index.tsx b/frontend/components/pages/error/index.tsx new file mode 100644 index 0000000..fd21e2a --- /dev/null +++ b/frontend/components/pages/error/index.tsx @@ -0,0 +1,48 @@ +import React, { FC } from "react"; +import { Box, Heading, Stack, Text, Button, Flex } from "@chakra-ui/core"; +import Link from "next/link"; + +interface IProps { + statusCode: number; +} + +const IndexPageComponent: FC = ({ statusCode }) => { + const heightOfNavbar: string = "74px"; + const containerPadding: string = "1rem"; + + const signOutButtonNode = () => { + return ( + + + + + + ); + }; + + return ( + + + + Nextjs Strapi Boilerplate + + {statusCode + ? `An error ${statusCode} occurred on server` + : "An error occurred on client"} + + + + {signOutButtonNode()} + + + + + + ); +}; + +export default IndexPageComponent; diff --git a/frontend/components/pages/feeds/add-new-feed-form.tsx b/frontend/components/pages/feeds/add-new-feed-form.tsx new file mode 100644 index 0000000..05ef151 --- /dev/null +++ b/frontend/components/pages/feeds/add-new-feed-form.tsx @@ -0,0 +1,107 @@ +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 ( + + ); + } + + 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 ( + + + {insertFeedError} + + + ); + }; + + return ( + + {errorNode()} + + + + What's on your mind? +