Skip to main content

3. Creating the Application Components

Now let's make some changes to our application. In this moment we are not going to use none UI framework. So, let's start creating some components.

Every application needs a Layout. So, let's create a Layout component. Create a folder called components/Layout and inside it create the file:

  • Layout/layout.tsx
components/Layout/layout.tsx

import Header from '../Header/header';
import Footer from '../Footer/footer';
import React, { ReactNode } from 'react';

interface LayoutProps {
children: ReactNode;
}

export default function Layout({ children }: LayoutProps) {
return (
<>
<Header />
<main>{children}</main>
<Footer />
</>
);
}

Hold on! It's not over yet. We need to create the Header and Footer components. So, let's create them.

  • Header/header.module.css
components/Header/header.module.css

.signedInStatus {
display: block;
min-height: 4rem;
width: 100%;
}

.loading,
.loaded {
position: relative;
top: 0;
opacity: 1;
overflow: hidden;
border-radius: 0 0 0.6rem 0.6rem;
padding: 0.6rem 1rem;
margin: 0;
background-color: rgba(0, 0, 0, 0.05);
transition: all 0.2s ease-in;
}

.loading {
top: -2rem;
opacity: 0;
}

.signedInText,
.notSignedInText {
position: absolute;
padding-top: 0.8rem;
left: 1rem;
right: 6.5rem;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
display: inherit;
z-index: 1;
line-height: 1.3rem;
}

.signedInText {
padding-top: 0rem;
left: 4.6rem;
}

.avatar {
border-radius: 2rem;
float: left;
height: 2.8rem;
width: 2.8rem;
background-color: white;
background-size: cover;
background-repeat: no-repeat;
}

.button,
.buttonPrimary {
float: right;
margin-right: -0.4rem;
font-weight: 500;
border-radius: 0.3rem;
cursor: pointer;
font-size: 1rem;
line-height: 1.4rem;
padding: 0.7rem 0.8rem;
position: relative;
z-index: 10;
background-color: transparent;
color: #555;
}

.buttonPrimary {
background-color: #346df1;
border-color: #346df1;
color: #fff;
text-decoration: none;
padding: 0.7rem 1.4rem;
}

.buttonPrimary:hover {
box-shadow: inset 0 0 5rem rgba(0, 0, 0, 0.2);
}

.navItems {
margin-bottom: 2rem;
padding: 0;
list-style: none;
}

.navItem {
display: inline-block;
margin-right: 1rem;
}

We won't go into details about the css.

Now let's focus on the header.tsx file. Open the header.tsx file and add the following code:

  • Header/header.tsx
components/Header/header.tsx

import Link from 'next/link';
import { signIn, signOut, useSession } from 'next-auth/react';
import styles from './header.module.css';

export default function Header() {
const { data: session, status } = useSession();
const loading = status === 'loading';

return (
<header>
<noscript>
<style>{`.nojs-show { opacity: 1; top: 0; }`}</style>
</noscript>
<div className={styles.signedInStatus}>
<p
className={`nojs-show ${
!session && loading ? styles.loading : styles.loaded
}`}
>
{!session && (
<>
<span className={styles.notSignedInText}>
You are not signed in
</span>
<a
href={`/api/auth/signin`}
className={styles.buttonPrimary}
onClick={(e) => {
e.preventDefault();
signIn();
}}
>
Sign in
</a>
</>
)}
{session?.user && (
<>
{session.user.image && (
<span
style={{ backgroundImage: `url('${session.user.image}')` }}
className={styles.avatar}
></span>
)}
<span className={styles.signedInText}>
<small>Signed in as</small>
<br />
<strong>{session.user.email ?? session.user.name}</strong>
</span>
<a
href={`/api/auth/signout`}
className={styles.button}
onClick={(e) => {
e.preventDefault();
signOut();
}}
>
{' '}
Sign Out
</a>
</>
)}
</p>
</div>
<nav>
<ul className={styles.navItems}>
<li className={styles.navItem}>
<Link href='/'>Home</Link>
</li>
<li className={styles.navItem}>
<Link href='/admin'>Admin</Link>
</li>
<li className={styles.navItem}>
<Link href='/reminder'>Reminder</Link>
</li>
</ul>
</nav>
</header>
);
}

If you look at the code above, you'll see that we're using the useSession hook to get the session data. We're also using the signIn and signOut functions to sign in and out of the application. And also we are using the status variable to check if the session is loading or not.

You will see we are using session?.user to check if the user is signed in or not. If the user is signed in, we will show the user's name and email address. If the user is signed in we will show the Sign Out button to log out of the application.

Inside in the return block code we are using React. And also, we are using the Link component from Next.js to navigate between pages.

And finally, let's create the Footer component. Open the components folder and create a new folder called Footer. Inside in the Footer folder, create these files:

  • Footer/footer.module.css
components/Footer/footer.module.css

.footer {
margin-top: 2rem;
}

.navItems {
margin-bottom: 1rem;
padding: 0;
list-style: none;
}

.navItem {
display: inline-block;
margin-right: 1rem;
}

  • Footer/footer.tsx
components/Footer/footer.tsx

import styles from '../Footer/footer.module.css';

export default function Footer() {
return (
<footer className={styles.footer}>
<hr />
<ul className={styles.navItems}>
<li className={styles.navItem}>
<a href='https://twitter.com/glaucia_lemos86'>Twitter</a>
</li>
<li className={styles.navItem}>
<a href='https://twitter.com/glaucia_lemos86'>Youtube</a>
</li>
<li className={styles.navItem}>
<a href='https://twitter.com/glaucia_lemos86'>Linkedin</a>
</li>
</ul>
</footer>
);
}

It's a simple footer component. But if you want to add more things to it, feel free to do it.

But what if the user is not logged in? So what happens? We have to create a page that says the user does not have permission to access the page. Shall we create it? Let's do it!

Inside the components folder, create a new folder called AccessDenied. Inside in this folder, create the file:

  • AccessDenied/access-denied.tsx
components/AccessDenied/access-denied.tsx

import { signIn } from 'next-auth/react';

export default function AccessDenied() {
return (
<>
<h1>Access Denied</h1>
<p>
<a
href='/api/auth/signin'
onClick={(e) => {
e.preventDefault();
signIn();
}}
>
You must be signed in to view this page
</a>
</p>
</>
);
}

Again! It's a simple component! 😊

We are going to use TypeScript in this application. So let's do it! Open the terminal and run the following command:

npm run build

And then run the following command:

npm run dev

You will see the screen it still the same. But why? Because we haven't created the pages yet. But let's make in the next section.