Hey, fellow developers!
I'm a full-stack web developer with a passion for sharing my web development journey with other devs. Recently, I’ve created a full stack Restaurant application where users can order food. Feel free to check it out on my GitHub page.
Moreover, I’ve published the tutorial of the project on my Youtube channel. You can reach the playlist here
Whether you're a seasoned developer or a curious learner, this tutorial series has something for everyone.
What technologies are used?
Backend:
Next.js App Router (API)
Database:
PostgreSQL (but you can choose any other database provider because we'll be using Prisma ORM)
Auth:
Auth.js (Next-Auth) with Prisma Adapter
Payment Gateway:
Stripe Custom Payments
Front-End Framework:
Next.js App Router (Pages)
UI libraries:
Tailwind CSS
State Management Library:
Zustand
File Storage:
Cloudinary
Design Part of the Restaurant App
In this part, we’ll design the application using reusable React components and Tailwind CSS. It’s a great tutorial to understand the difference between Next.js server-side components and client-side components. You’ll also learn how to design a fully responsive app using Tailwind classes.
The design consists of seven pages and ten components.
-
src
-
app
- page.tsx (Homepage)
- cart
- page.tsx
- login
- page.tsx
- menu
- page.tsx
- [categoryId]
- page.tsx
- orders
- page.tsx
- product
- [id]
- page.tsx
- [id]
-
components
- CartIcon.tsx
- CountDown.tsx
- Featured.tsx
- Footer.tsx
- Navbar.tsx
- Menu.tsx
- Notification.tsx
- Offer.tsx
- Price.tsx
- Slider.tsx
-
app
Full Stack Part of the Food Ordering App
In this part, we’ll create the API route and communicate with the front end. I preferred PostgreSQL, but as I mentioned above, you can use any other database because we won’t write a single line of SQL code thanks to Prisma. We’ll make all the CRUD operations using Prisma Client easily.
-
src
-
app
- api
- create-intent
- route.ts
- confirm
- route.ts
- categories
- route.ts
- orders
- route.ts
- products
- route.ts
- auth
-[…nextAuth]
- route.ts
- create-intent
- api
-
docker
- docker-compose.yml
-
utils
- auth.ts
- connect.ts
- store.ts
-
app
For the authentication, we’ll be using Next-Auth Prisma Adapter and it’ll handle all the auth process including sessions, user accounts, tokens, role based authorizations etc.
To do that, you need to create a schema file in prisma/schema.prisma similar to this one:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
shadowDatabaseUrl = env("SHADOW_DATABASE_URL") // Only needed when using a cloud provider that doesn't support the creation of new databases, like Heroku. Learn more: https://pris.ly/d/migrate-shadow
}
generator client {
provider = "prisma-client-js"
previewFeatures = ["referentialActions"] // You won't need this in Prisma 3.X or higher.
}
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String? @db.Text
access_token String? @db.Text
expires_at Int?
token_type String?
scope String?
id_token String? @db.Text
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
}
model Session {
id String @id @default(cuid())
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
isAdmin Boolean @default(false)
image String?
accounts Account[]
sessions Session[]
}
model VerificationToken {
identifier String
token String @unique
expires DateTime
@@unique([identifier, token])
}
We use this standard schema for the Prisma adapter; you can find it in the official documentation.
I’ve only added the isAdmin field in the user model to give a role for users. I use a boolean because my application has only two roles (admin/regular user).
Source:
Role-Based Authentication with Next.js and Prisma
After completing the authentication and CRUD operations, we’ll start adding the cart functionality. In the project, Zustand was my preference for state management.
If you prefer a simple and concise state management solution, Zustand might be a better fit.
Creating a Zustand store is as simple as calling a single function, passing a function that defines the store’s initial state and actions.
Source:
And finally, we’ll implement Stripe custom payments with the shipping option, and users will be able to create new orders and complete the payment process.
I hope it was useful. If you want to learn more about web development and practice with real-world projects, you can check out my channel and other posts.
Other Dev.to Posts
🎥 Full Stack Youtube Clone (5 hours free tutorial)
🛍️ Full Stack E-Commerce App (+8 Hours free tutorial)
📺 Full Stack Netflix App (+7 Hours free tutorial)
🧑🤝🧑 Full Stack Social Media App (+7 Hours free tutorial)
Lama Dev
🔥 Lama Dev YouTube Channel
⚡️ Lama Dev Instagram
👾 Source Code
Top comments (1)