Frontend Serverless with React and GraphQL

Start at the beginning and work your way through this project. The code for each step as well as the finished project can be found in the Github repository.


23. Add Login / Logout to the Navbar

Objective: Add user login and logout button to the site's navbar.

First, let's do a quick housekeeping. Add @ts-ignore to the line before export function useFetchUser({ required } = {}) { to prevent it from complaining in the utils/user.ts file we just created.

Now, we will now use the new useFetchUser hook that we just created to selectively show either the login or the logout button in the navbar, based on whether the user has logged in.

components/layout/MainNavbar.tsx

import styled from 'styled-components';
import { Layout, Menu } from 'antd';
import Link from 'next/link';
import { useFetchUser } from '../../utils/user';
const { Header } = Layout;
const TitleContainer = styled.div`
${({ theme }) => `
background-color: ${theme['header-color']};
width: 50%;
display: flex;
align-items: center;
@media (max-width: 890px){
visibility: hidden;
width: 0;
}
`}
`;
const Title = styled.div`
${({ theme }) => `
text-align: left;
display: flex;
line-height: 50px;
div {
width: 100%;
padding-left: ${theme['padding-small']};
}
h2 {
display: inline;
color: inherit;
}
img {
width: 64px;
}
p {
line-height: 0;
}
`}
`;
const StyledHeader = styled(Header)`
${({ theme }) => `
background-color: ${theme['header-color']};
border-bottom-color: ${theme['header-border-color']};
border-bottom-right: 1px;
border-bottom-style: solid;
text-align: right;
display: flex;
li {
font-size: ${theme['font-size-md']};
}
`}
`;
const StyledMenu = styled(Menu)`
border-bottom-width: 0px;
width: 50%;
@media (max-width: 890px) {
width: 100%;
}
`;
export const MainNavbar = () => {
const { user, loading } = useFetchUser();
return (
<StyledHeader>
<TitleContainer>
<Title>
<img src="/logo.svg" alt="Next Chop Logo" />
<div>
<h2>The Next Chop</h2>
<p>A recipe discovery app powered by Next.js</p>
</div>
</Title>
</TitleContainer>
<StyledMenu
theme="light"
mode="horizontal"
style={{ lineHeight: '64px' }}
>
<Menu.Item key="/">
<Link href="/">
<a>Home</a>
</Link>
</Menu.Item>
{user && !loading
? [
<Menu.Item key="/api/logout">
<Link href="/api/logout">
<a>Logout</a>
</Link>
</Menu.Item>,
]
: [
<Menu.Item key="/api/login">
<Link href="/api/login">
<a>Login</a>
</Link>
</Menu.Item>,
]}
</StyledMenu>
</StyledHeader>
);
};

Note that for the ternary user ? [ <Component/> ] : [ <Component /> ] we use brackets instead of paretheses because we plan to add additional menu items into these conditionals and we want to set it up as returning an array of components rather than a single component right from the start.