Key Concepts
- Full Stack Web Development: Building both the front-end (user interface) and back-end (server-side logic and database) of a web application.
- Next.js: A React framework for building server-rendered and statically generated web applications.
- Prisma: An Object-Relational Mapper (ORM) for Node.js and TypeScript, simplifying database interactions.
- Tailwind CSS: A utility-first CSS framework for rapidly designing user interfaces.
- Neon: A serverless PostgreSQL database platform.
- NextAuth.js (Next O): An authentication library for Next.js applications.
- UploadThing: A service for handling file uploads in web applications.
- React Google Maps: A library for integrating Google Maps into React applications.
- Radix UI: A set of accessible and unstyled React components.
- React DND (Drag and Drop): A library for implementing drag-and-drop functionality in React applications.
- Server Actions: Functions that run on the server in Next.js, allowing for secure data mutations.
- Prisma Transactions: A mechanism to ensure that multiple database operations are executed atomically.
Project Setup and Initial Configuration
- Creating a New Next.js App: Using
npx create-next-appto scaffold a new Next.js project with TypeScript, ESLint, Tailwind CSS, and the app router. - Installing Dependencies: Installing various packages using
npm install, including:prisma: For database interactions.next-auth: For user authentication.@next-auth/prisma-adapter: To connect NextAuth.js with Prisma.uploadthing: For image storage.react-google-maps/api: For Google Maps integration.@radix-ui/react-*: For pre-built UI components.@dnd-kit/*: For drag-and-drop functionality.
- Configuring Tailwind CSS: Defining custom colors and classes in
tailwind.config.jsusing OKLCH color definitions for backgrounds, cards, text, buttons, inputs, and borders. - Creating a Navbar Component: Building a navigation bar with a logo, website title, links to "My Trips" and "Globe" pages, and a "Sign In" button.
Authentication Setup with NextAuth.js and Prisma
- Setting up Neon Database: Creating a new project and database in Neon, a serverless PostgreSQL platform.
- Prisma Initialization: Running
npx prisma initto generate the Prisma schema and client. - Connecting to Neon: Copying the connection string from Neon and pasting it into the
.env.localfile asDATABASE_URL. - NextAuth.js Configuration:
- Creating an
auth.tsfile at the root of the project. - Using the
NextAuthfunction to configure authentication providers (GitHub) and the Prisma adapter. - Creating a
lib/prisma.tsfile to instantiate the Prisma client with proper type definitions. - Defining the necessary models (User, Account, Session, VerificationToken) in
schema.prismafor NextAuth.js to store user data. - Running
npx prisma migrate devto create the corresponding tables in the Neon database. - Running
npx prisma generateto update the Prisma client with the new models.
- Creating an
- GitHub OAuth Setup:
- Creating an OAuth app in GitHub Developer Settings.
- Obtaining the Client ID and Client Secret.
- Adding the
GITHUB_IDandGITHUB_SECRETto the.env.localfile. - Generating a NextAuth.js secret using
npm exec nextauth secretand adding it to.env.localasNEXTAUTH_SECRET.
- Creating API Routes for NextAuth.js: Creating the necessary API routes in
app/api/auth/[...nextauth]/route.tsto handle authentication requests. - Implementing Sign-in and Sign-out Actions:
- Creating a
lib/auth-actions.tsfile withloginandlogoutfunctions. - Using the
signInandsignOutfunctions from NextAuth.js. - Adding an
onClickhandler to the "Sign In" button in the Navbar component to call theloginfunction. - Using the
use clientdirective to make the Navbar component a client component.
- Creating a
- Conditional Rendering in Navbar: Using the
getSessionfunction to determine if a user is authenticated and conditionally rendering the "Sign In" and "Sign Out" buttons, as well as the "My Trips" and "Globe" links.
Building the Travel Planner App
My Trips Page
- Creating the Trips Page: Creating a
trips/page.tsxfile to display the user's planned trips. - Authentication Check: Using the
getSessionfunction to ensure that only authenticated users can access the page. - UI Structure: Building the basic UI structure with a title ("Dashboard"), a "New Trip" button, and a welcome message.
- Radix UI Components: Importing and using pre-built UI components from Radix UI, such as
Button,Card,CardHeader, andCardContent. - Fetching Trips from Database: Using Prisma to query the database and retrieve all trips associated with the currently logged-in user.
- Displaying Trips: Displaying the trips in a grid layout, showing the title, description, start date, and end date for each trip.
- Conditional Rendering: Displaying a message if the user has no trips planned yet.
New Trip Page
- Creating the New Trip Page: Creating a
trips/new/page.tsxfile to allow users to create new trips. - Form Structure: Building a form with input fields for the trip title, description, start date, and end date.
- Date Input: Using
<input type="date">for selecting the start and end dates. - Required Fields: Adding the
requiredattribute to all input fields. - Create Trip Button: Adding a "Create Trip" button to submit the form.
- Prisma Schema Update: Adding a
Tripmodel to theschema.prismafile with fields forid,title,description,imageURL,startDate,endDate,userId,createdAt, andupdatedAt. - Database Migration: Running
npx prisma migrate devto create theTriptable in the Neon database. - Prisma Client Generation: Running
npx prisma generateto update the Prisma client with the newTripmodel. - Server Action for Creating Trips:
- Creating a
lib/actions/create-trip.tsfile with acreateTripfunction. - Using the
use serverdirective to mark the function as a server action. - Extracting data from the form data.
- Validating the input data.
- Converting the start and end dates to JavaScript
Dateobjects. - Using Prisma to create a new
Triprecord in the database. - Redirecting the user to the
tripspage after successful creation.
- Creating a
- Integrating the Server Action:
- Passing the
createTripfunction to theactionprop of the form. - Using the
useTransitionhook to handle the pending state of the form submission. - Disabling the "Create Trip" button while the form is submitting.
- Passing the
Image Uploading with UploadThing
- UploadThing Account Setup: Creating an account on UploadThing and creating a new app.
- API Key Retrieval: Obtaining the API key from UploadThing and adding it to the
.env.localfile. - UploadThing API Route:
- Creating an
app/api/uploadthingfolder withroute.tsandcore.tsfiles. - Copying the code from the UploadThing documentation into these files.
- Creating an
- UploadThing Configuration:
- Replacing the fake authentication function with the actual
getSessionfunction from NextAuth.js. - Adding the user ID to the metadata.
- Replacing the fake authentication function with the actual
- UploadThing Component:
- Creating a
lib/uploadthing.tsfile with theUploadButtonandUploadDropzonecomponents.
- Creating a
- Integrating the UploadButton:
- Adding the
UploadButtoncomponent to thenew-trip/page.tsxfile. - Specifying the
endpointas "imageUploader". - Implementing the
onClientUploadCompletecallback to handle the uploaded image URL. - Implementing the
onUploadErrorcallback to handle upload errors.
- Adding the
- Image Preview: Displaying a preview of the uploaded image using the
next/imagecomponent. - Next.js Image Configuration: Adding the UploadThing hostname to the
remotePatternsarray innext.config.js. - Passing the Image URL to the Server Action: Appending the image URL to the form data in the
new-trip/page.tsxfile. - Updating the Create Trip Action: Modifying the
createTripfunction inlib/actions/create-trip.tsto retrieve the image URL from the form data and save it to the database.
Trip Details Page
- Creating the Trip Details Page: Creating a
trips/[tripId]/page.tsxfile to display the details of a specific trip. - Dynamic Route: Using a dynamic route parameter
[tripId]to access the ID of the trip. - Server Component: Making the page a server component to fetch the trip data from the database.
- Authentication Check: Using the
getSessionfunction to ensure that only authenticated users can access the page. - Fetching Trip Data: Using Prisma to query the database and retrieve the trip data based on the
tripId. - Client Component: Creating a
components/trip-detail.tsxfile to build the UI for the trip details page. - Passing Data to Client Component: Passing the fetched trip data as props to the
TripDetailClientcomponent. - UI Structure: Building the UI structure with a banner image, a header card, and tabs for "Overview", "Itinerary", and "Map".
- Conditional Rendering: Displaying a message if the trip is not found or if the user is not authorized to view the trip.
- Tabs Component: Using the
Tabscomponent from Radix UI to create the tab navigation. - Overview Tab: Displaying the trip summary, dates, and destinations in the overview tab.
- Map Integration: Integrating Google Maps into the overview tab to display the trip locations.
Location Management
- Prisma Schema Update: Adding a
Locationmodel to theschema.prismafile with fields forid,title,latitude,longitude,tripId, andorder. - Database Migration: Running
npx prisma migrate devto create theLocationtable in the Neon database. - Prisma Client Generation: Running
npx prisma generateto update the Prisma client with the newLocationmodel. - Creating the New Location Page: Creating a
trips/[tripId]/itinerary/new/page.tsxfile to allow users to add new locations to a trip. - Form Structure: Building a form with an input field for the location address.
- Add Location Button: Adding an "Add Location" button to submit the form.
- Server Action for Adding Locations:
- Creating a
lib/actions/add-location.tsfile with anaddLocationfunction. - Using the
use serverdirective to mark the function as a server action. - Extracting the address from the form data.
- Using the Google Maps Geocoding API to retrieve the latitude and longitude for the address.
- Using Prisma to create a new
Locationrecord in the database. - Redirecting the user to the trip details page after successful creation.
- Creating a
- Google Maps Geocoding API:
- Creating a
lib/geocode.tsfile with agetCountryFromCoordinatesfunction. - Using the Google Maps Geocoding API to retrieve the country and formatted address for a given latitude and longitude.
- Creating a
- Integrating the Server Action:
- Passing the
addLocationfunction to theactionprop of the form. - Using the
useTransitionhook to handle the pending state of the form submission. - Disabling the "Add Location" button while the form is submitting.
- Passing the
- Displaying Locations on the Map:
- Modifying the
TripDetailClientcomponent to fetch the locations associated with the trip. - Passing the locations to the
Mapcomponent. - Using the
react-google-maps/apilibrary to display the locations on the map.
- Modifying the
- Itinerary Tab:
- Creating a
components/sortable-itinerary.tsxfile to display the list of locations in the itinerary tab. - Using the
react-dnd-kitlibrary to implement drag-and-drop functionality for reordering the locations.
- Creating a
- Reordering Itinerary:
- Creating a
lib/actions/reorder-itinerary.tsfile with areorderItineraryfunction. - Using the
use serverdirective to mark the function as a server action. - Using Prisma transactions to update the order of the locations in the database.
- Integrating the server action with the
SortableItinerarycomponent.
- Creating a
Globe Page
- Creating the Globe Page: Creating a
globe/page.tsxfile to display a 3D globe with pins for visited countries. - React GlobeGl Library: Using the
react-globe.gllibrary to render the 3D globe. - Fetching Visited Countries:
- Creating an API route
app/api/trips/route.tsto fetch the locations of all trips and extract the unique countries. - Using the Google Maps Geocoding API to retrieve the country for each location.
- Creating an API route
- Displaying Visited Countries: Displaying a list of the visited countries in a card on the globe page.
- Pinning Countries on the Globe: Using the
pointsDataprop of thereact-globe.glcomponent to pin the visited countries on the globe.
Conclusion
The video provides a comprehensive guide to building a full-stack travel planner application using a modern tech stack. It covers everything from setting up the project and configuring authentication to implementing complex features like image uploading, Google Maps integration, drag-and-drop functionality, and 3D globe visualization. The video emphasizes best practices, such as using server actions for secure data mutations and Prisma transactions for atomic database operations. By following the steps outlined in the video, developers can gain valuable experience in building real-world web applications with Next.js, Prisma, Tailwind CSS, and other cutting-edge technologies.
AI summaries can miss context or contain errors. Check important details against the original video.





