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.
26. Add a Favorites Page
Objective: Add a recipes list page at the route `/favorites` that contain all the items that the user has liked.
Now that we have a way for users to like recipes, let's create a page that will list all of the user's favorite recipes. This favorites page will be similar to the home page except we pass different props into the <RecipesList>
component- in particular the different queryType and options object.
Let's create a favorites page:
pages/favorites.tsx
import { MainLayout } from '../components/layout/MainLayout';import styled from 'styled-components';import { useFetchUser } from '../utils/user';import * as _ from 'lodash';import { Loading } from '../components/notify/Loading';import Router from 'next/router';import { RecipesList, queryEnum } from '../components/RecipesList';const StyledHeader = styled.h1`${({ theme }) => `font-size: 2em;text-align: left;padding: ${theme['padding-small']} ${theme['padding-small']};`}`;const Favorites = () => {const { user, loading: isFetchUser } = useFetchUser();const owner = _.get(user, 'sub');const options = owner ? { variables: { where: { user: owner } } } : {};if (isFetchUser) return <Loading />;if (!user) {Router.replace('/');}return (<MainLayout title="Recipes"><StyledHeader>My Favorites</StyledHeader><RecipesListparentRoute="recipe"queryType={queryEnum.userLikes}options={options}/></MainLayout>);};export default Favorites;
Next, as a bit of cleanup, add the <Loading />
component to the my-recipes/index.tsx page. Just like the home page, we don't want to load any recipes lists on a page before the loading has completed.
pages/my-recipes/index.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><StyledMenutheme="light"mode="horizontal"style={{ lineHeight: '64px' }}><Menu.Item key="/"><Link href="/"><a>Home</a></Link></Menu.Item>{user && !loading? [<Menu.Item key="/favorites"><Link href="/favorites"><a>Favorites</a></Link></Menu.Item>,<Menu.Item key="/my-recipes"><Link href="/my-recipes"><a>My Recipes</a></Link></Menu.Item>,<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>);};