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.