Table of Contents
Introduction
Database & Routes
Setup Next.js App
Scott uses the Create Next App CLI tool to scaffold a new application. Some additional dependencies are added to the project that will be needed as the application is built. A brief tour of the application structure is also shared in this lesson.Setup a Postgres Database on Railway
Scott creates a free, hosted Postgres database on Railway.app. The connection string is saved in an ENV file in the project. The Prisma ORM, which will connect to the database, is introduced.Setup Database Schema with Prisma
Scott builds the Prisma schema for the applications. The models include users, projects, and tasks. The Prisma extension for VSCode adds syntax highlighting and formatting for .prisma files.Sync Schema & Setup Prisma Client
Scott runs a migration on the database. Prisma creates an SQL file with the instructions for syncing the changes from the schema. A helper script for caching the Prisma client is also created.Seeding the Database
Scott creates a seed script to populate the database. This script can be run after migrations to ensure the database contains the correct data for testing the application.Routes & Route Groups
Scott introduces how routing works in Next.js 13. The page.tsx file in a directory will be loaded when that route segment is browsed. Route groups can be created by wrapping the directory name in parentheses.
UI Components
GlassPane Container Component
Scott creates the GlassPane component that adds the diffused or blurred effect to the background. Since this is a container component, it is passed a parameter for the children it should render.Root Layout Components
Scott implements the root layouts for both the dashboard and auth route groups. Both layouts use the GlassPane component to render the children for that specific route group.Setup Styles & Tailwind CSS
Scott creates a tailwind.config.js file to point Tailwind CSS at the content directories and override any theme properties. The base, components, and utilities styles are imported to the global.css file.Button Component with Variants
Scott creates a Button component and uses a library to allow variants to be applied through the component's props. Variants are added for the button's intent (primary, secondary, and tertiary) and size (small, medium, and large).Card & Input Components
Scott creates the Card and Input components. The Card component will display projects and tasks in the interface. The Input component will be reused in Form elements throughout the application.SidebarLink Component
Scott builds the SidebarLink component, the first "client component" in the application. It will be rendered inside a server component, so the potential icons for each link are imported. An issue with Tailwind CSS is also fixed in this lesson.Sidebar Component
Scott creates the Sidebar component, which will display the links for the application. An array of data for each link is mapped over to generate the SidebarLink components.
Authentication
Authentication Handlers
Scott writes the client-side authentication handler functions for registering and signing in to the application. These handlers will be called from client-side components and interact with the API endpoints inside the Next.js pages directory.AuthForm Component
Scott scripts an AuthForm component that can be reused for the login and registration forms. A mode property is set based on where the form is being used.AuthForm Pages
Scott adds the AuthForm component to the register and sign in pages.Password Management
Scott uses the bcrypt npm package to create two password authentication utility functions. The hashPassword function receives a plain-text password and returns a hashed version. The comparePasswords function receives a plain-text password and a hashed password. It determines if the plain-text version matches the hash.JSON Web Tokens
Scott creates utility functions for creating, validating, and accessing authentication JWT Tokens. A JWT token is created from a user's ID and email when they sign in. Environment variables for the JWT_SECRET and COOKIE_NAME are also made.Register API Route
Scott writes the route handler function for the register route. The handler verifies the method is POST and uses the POST data to create a User object. A JWT is created and serialized in the cookie.Sign In API Route
Scott completes the route handler for the signin route. The handler finds the user in the database, compares the saved hashed password with the password submitted from the form, and logs the user in if the password is valid.Middleware
Scott introduces middleware which intercepts all requests to the server. A middleware function can manually check if it should run on a route, or a "matches" configuration object can be exported with a list of valid paths. This middleware function verifies a valid JWT exists before allowing access to the protected resources.Testing Authentication Routes
Scott tests the authentication routes. The home route is now protected and redirects to the login screen. Edge functions are also discussed in this lesson.
Dashboard Page
Dashboard Home Page
Scott builds the dashboard home page. A utility function to slow down network requests by delaying API responses is also created in this lesson.Greetings Component
Scott creates the Greetings component, which displays the current user's name across the top of the application. The delay utility function is used to slow down the loading of the component. Since this is a server component, that delay must finish before the page can be loadedGreetingsSkeleton Component
Scott adds a GreetingsSkeleton component, which displays a skeleton UI or "shimmer" while the entire component is loading. This provides valuable context to the user for what to expect and makes the network delay less noticeable.ProjectCard Component
Scott demonstrates how to leverage the types created by Prisma while creating a component for the project cards. Leveraging the existing types eliminates redundancy in type declarations or the need to refactor when there are changes to the schema.Fetching Project Data
Scott explains why data fetching needs to occur in the parent containing the project cards and not in each individual card. Project card data is fetched in the application. The database is reset and reseeded so the seed user's password is hashed.Data Loading & Server Components
Scott explains how data is loaded with server components and outlines different strategies for loading projects without blocking the initial load from the server.TaskCard Component
Scott implements the TaskCard component. The component will display the next five tasks due across all projects. When a project is selected, this component will be reused to display tasks for a specific project.Loader Component
Scott creates a loader component for the home page. Next.js recognizes the naming convention used for the component, and it's automatically uses it to handle the delay between page load and when the component has received data.
Project Page
Creating the Project Page
Scott implements the project page, which displays a list of tasks for a specific project. The page uses the ID parameter passed in the URL to query the project data. The TaskCard component is reused to display the tasks.New Project API Handler
Scott writes the API handler for creating new projects. A post request is sent to the handler. Since projects are loaded server-side, the application will need to reload for the new project to be displayed.Modal Client Component
Scott builds the UI for the NewProject modal component. Since the component renders a form and has client-side state, the "use client" directive is added.