Loading video player...
Imagine learning how to use the most in-
demand web development framework to
build any website that you want. Not
only that, but be able to add skills to
your resume that will get you to the top
of every job application. If you want
that, then learning XJS effectively is
the only way. And there is no better way
to learn Next.js than by building a real
project. So for that reason, in this
video, we will learn how to build a
fullstack Nex.js JS application by
practicing all of the important NexJS
concepts like server actions
authentication, route handling, server
components, and much more. We will build
a beautiful inventory management app
with an interactive dashboard that you
will be able to add directly into your
resume and impress your employers. Now
if you really want to learn NextJS to
the fullest of its capabilities, I
actually just released my full next
level Nex.js JS course for beginners.
This course will take you from a
complete Nex.js beginner to
understanding all of the necessary core
concepts required for you to call
yourself a master at Nex.js. This course
contains three projects for you to build
and it comes with my full assistance for
all of your questions. If you are
interested in checking it out, just go
to www.webdevultra.com/nextjs
or just click the link in the
description. We have a 20% discount code
for the first 100 people. And this
discount went away pretty fast the last
time we released our ReactJS course. So
make sure to check it out. And now that
we are ready, let's get into the video.
Okay, everyone. Now to get started, we
want to set up our Nex.js project. To
set up Nex.js, you have a couple
commands that you can use, but the most
common one is going to be the create
next app command. So I'm going to come
over here. I'm going to open up my
terminal and run the command npx create
next app. Now, what this is going to do
is it's going to start prompting us with
some questions. For example, what is the
project named? Uh, I want to create the
project inside of the directory I'm
already inside of. So, I'll just put a
dot to create that. Uh, we're going to
be using TypeScript in this video. So
I'm, going to, say, yes, to, that., Uh,, we
want to use ESLint even though we don't
really mind uh any of the other options
as well. We will be using Tailwind CSS.
So that's a yes for that too. I usually
don't like to structure my apps with a
source directory. Some people do. Uh
that's whatever. It depends on what you
prefer. I won't. So I'll click no. Uh we
definitely want to use the app router.
Uh we'll definitely want to use tuber
pack. No for import alias. And that
should be good to go. Now when we create
our app, we finishes building. We will
just run npm rundev. And if I open up uh
my browser and I refresh the page, you
should see that we should have the
boilerplate code running. Now, the first
thing we want to do is we want to
structure our project. The way we're
going to do this is we're going to come
here to our project and we're going to
first create the structure for our
routes. Now, based on what you saw in
the demo of this video, we are building
an inventory management app. And in that
app, we're going to have a variety of
different routes. The first route we're
going to have is going to be the
dashboard route. So, I'll create a
folder over here. And inside of it, I
will later create a component that will
render the UI for that uh route. But for
now, we'll just keep it empty just for
our, um, understanding, of, at least, a
structure. The next thing is I'll create
the folder for the add product. Now the
add product route is going to be a page
where it has a form and the user can uh
add a product to their inventory. Then
the next one it's going to be the
inventory route. So here we're going to
add the inventory route. This is where
they can see their entire inventory.
They can filter through it and um delete
items from their inventory if they want
to. Now the last two are going to be
related to the user's account. The first
one is the settings. That's going to be
just a settings page where the user is
going to be able to um see their
information, update their password, sign
out, delete their account, that kind of
stuff. And we're going to have a sign in
page
uh where the user will be able to sign
in. Now the initial route is going to be
in this page.tsx. Now this page over
here is the homepage and it is what you
are seeing over here. You see it's
completely empty right now. Uh but I
don't really care about what you put in
this homepage. It could be like a
landing page. You can make it into
whatever you want. I like a minimalist
design. However, in this video, this is
not part of what we're focusing on. We
kind of want to focus on the dashboard
on the inventory, on all of the stuff
that happens after you sign in. So, what
I'm going to do with this is I already
have the code for the UI that I wrote
for for this page specifically. And if
you want to use the same code, feel free
to do so. Again, this is the only page
in this whole project where I'm not
going to show myself manually writing
every single uh line of it just because
it is basically just uh HTML or JSX with
Tailwind CSS. And most likely you don't
even want to have the same landing page
as me. But if you do, just go for the
description and you'll be able to find
the code for this video. Now, what I
built here is just a simple UI where
there's a description for the project
for the website, a little description.
Uh, this is the title, this is the
description, and then there's two
buttons. This learn more really doesn't
do anything, but the signin should take
us to a sign-in page. Now, after you're
done just copy and pasting this, here is
where things gets interesting. We want
to set up authentication in our project.
Now to do that, we're actually going to
be using two different services that are
going to help us. Both services are
absolutely free and are great and work
well together. The first service is
Neon. The first service is Neon. And
Neon is a serverless Postgress SQL
database where you can really quickly uh
set up a database for your project that
is going to be hosted for you. It is
extremely fast. It scales really well.
And if you want to check them out, just
go ahead and click the link in my
description. They are completely free
and they're going to be what we're going
to be using in this project. I use Neon
so many times. It is great. Uh you'll
log into your account and you'll be able
to go into the console and here you're
able to create new projects which then
come with new databases that you can use
for your own projects. Now this is what
we're, going to, be, using, to, store, data.
Now for authentication, we're going to
be using a service called stack off. And
the reason why I chose Stack O for this
video is because it has a bunch of
pre-made uh authentication components
that some other libraries might not
have. And also it actually has great
integration with Neon. Neon now has um
an authentication service where
basically you connect Neon uh you
connect your stack off to Neon and you
can utilize uh Neon as the place where
you handle all your authentication for
your project. So everything is going to
be super simple and seamless. So to get
things started in our project, we want
to allow the user to sign in. But to
even do that, we need to set up Neon for
our application. So let's get started.
I'm going to click here on new project.
And we'll give a name for this project.
I'm going to call it inventory
management app. We're going to keep the
Postgress version as 17. I'm going to
choose AWS. And the location, you should
definitely choose the location which is
going to be the closest to wherever all
your users are going to be uh to get the
best connection. I am in the west. So
I'm, going to, choose, AWS, West, uh, 2, which
is in Oregon. It's kind of close to
where I am. Perfect. I created this and
immediately we have a database. Now on
Neon you can find your database tables
on the tables section over here on the
left. You see, we have absolutely no
tables in our database, but that's going
to change because what we want to do is
we want to come into our project and we
want to set up the database tables for
our uh inventory management app. Now
whenever you have a project that uh
interacts with a database table, you
definitely want to utilize an object
relation. No, you definitely want to
utilize what is known as an ORM. and ORM
will help you execute your database
queries, your mutations, whatever you're
doing to your database, it's going to
make it a thousand times easier. And
there's so many options out there, but
one of the most famous ones and the one
of the most secure ones is Prisma. So
Prisma, is, what, we're, going to, be, using
for this project, and it's going to help
us connect our project to our uh Neon
database. So to connect Prisma to set up
Prisma to our project, what we need to
do is we need to open up our terminal uh
open up a new tab and we need to run npx
Prisma init. Now if you don't have
Prisma created in your project, it will
or if you don't have it installed in
your computer, it will say you need to
install Prisma uh in order to continue.
You press Y or you just press enter.
It's going to start setting it up. And
immediately you'll notice that what it
does is the following. First things
first, it creates this uh Prisma folder
in your project which inside of it there
is a schema.prisma.
Now what this will do is it is going to
uh allow us to define how our database
tables are going to look like, how
they're modeled in the Prisma language
which will then allow us to push those
changes. And since we're going to
connect our database table in neon
those changes will appear over here so
that you don't need to manually create
them with the UI. Perfect. Now the
second thing that that command did is it
created av
file. This file now has a variable
called database URL with a huge link.
What we want to do is we want to replace
that link with the database URL from our
database on Prisma. Now to do that
we'll go to our dashboard. We'll click
on connect and you'll see that we should
see this connection string over here.
We'll copy the string directly
and then we're going to come back here
and we're going to delete whatever was
here before and replace it with the
string that we just copied. Perfect. Now
every time we make a change to our
schema over here though and push those
changes uh those changes should be
reflected on our u neon database. Now
let's go back over here and let's think
about what we're trying to create for
this project. Now in this project we
want to keep track of two pieces of
information. The first one is we want to
keep track about information about the
user and the second thing is keeping
track about information related to the
products. Right? So uh a product will
have for example a um the name of the
product. It will have a SKU value to it.
It will have a price, the amount of
quantity that we have of that product.
Also whoever created when they created
that product, all the pieces of
information. The second thing is we need
to keep track of the users in our
project. However, since we are using
stack off with neon, we don't need to
create a table for users. That table
will exist over here. Now I'm going to
click on enable neon o and it is going
to enable neon o into our project and we
will be able to set it up. Now how are
we going to do that? Well the first
thing we do is we go here to the
configuration and we see that there are
a bunch of environment variables that we
need to put into our project. The first
thing is we're going to click on copy
snippet. We're going to come back here
to our uhv file and we're just going to
paste that snippet. I just realized that
we didn't even need to manually copy the
link that we had before because the
snippet just gives it to us. So I can
just delete this what we put before
because it's the same thing and we'll
keep it more organized this way. So the
first are environment variables related
to uh stack O. So, we have a stack O
project ID, a stack publishable client
ID or key, and a stack secret server
key. Make sure you don't use the exact
same values as me because you might
think that that's uh obvious, but trust
me, people do use the same uh
environment variables as me. So, don't
do that. I'm going to delete this
project right after so that you guys
don't actually have access to this
information. Now that we have the
configuration variables created, what we
want to do is we want to create the
infrastructure for having stack off work
in our project. We're going to let the
schema.prisma file be whatever it is
right now until we have to deal with
actual products and then we're going to
create the table for it. But for now
we'll just focus on the users. Now to
set up stack O, we actually can use a
command on our terminal that it is going
to generate it for us. So I'm going to
paste the command here. It is npx at
stackframe/initstack
dot double dash no browser. When we run
this command, it is going to start
asking us some questions. It says
welcome to stack off. It knows it is an
X.js project and it's asking if it is if
we want to install it. I'm going to
press enter. So it's going to start
installing all the dependencies that are
necessary to set up stack off. And when
it's done, you'll see that it says
commands executed and it specifies that
it made changes to some of the files.
Now, let's take a look at what it did.
So, first things first, it created here
a folder in our app called handler and
it created a page.tsx that includes this
over here. Now, what exactly is this?
Well, with Stack O, they actually set up
a bunch of routes for us like the
sign-in route if we want to the account
settings route if they if we want to
access that as well that we can access
related to the user authentication. And
with this handler over here, it is
basically calling this stack handler
component from stackframe to be able to
handle what is shown to all of those
routes. So, this is something that you
don't touch. It is part of what they
create. The second thing is they created
a loading.tsx
and we are going to actually make our
own loading.tsx. We're going to make it
customized for this project. So we're
not going to be touching that right now.
The next thing is it created this stack
folder. And in the stack folder there's
a client and a server file. And this is
great because each of them will contain
this variable called the stack server
app or in this case for the client is
the stack client app. And they are used
to access uh stack O and its features
through either server or client
components. So for example with the
client.sx if you have if you need to
access authentication information in any
component that um is a client component
like a form component or anything like
that you'll use this. If you're in a
server component, which is 99% of the
components we're going to be building in
this app, you will be using the stack
server app. Now, why are we building our
app with mostly server components? One
of the main benefits with Nex.js is the
fact that it is server side rendered.
And the best way you can maximize the
benefits of Nex.js JS is for you to
build your app in a way such that most
of your app is server side rendered and
then there's going to be a minority of
it some small components that are going
to be client side because you have to
have client side functionality in an app
uh in most cases like so if you have a
form or anything that relates that needs
to access a react hook or anything like
that we will be creating a client
component for that but that's going to
be a minority part of our project.
Great. So, now that we set up stack O
we can actually start building the
sign-in page. And the sign-in page is
going to be super simple. I'm going to
click here on new file. I'm going to
create a page.tsx. And we'll be able to
start building the UI for this file. So
I'm going to say export default
function
signin page.
And in here, we want to return some
simple UI. The first thing is I want to
return a div that has an inner div
inside of it. And the top div will have
some class names to it. The first is
we're setting a minimum height of the
screen so that it's the full page. We're
setting it to have a display flex. We're
going to center the items so that
they're in the middle of the screen and
also uh on both horizontal and vertical
um so that it's actually in the middle
of the screen. The second thing is we
want to put inside of this div the
signin component. Now this is where 99%
of our UI for the signin page is going
to come from. You see immediately when I
open this up, this is what we see. This
is great, right? This is all of the UI
for both signing up with GitHub, signing
in with Google, signing in with your
email password that you need to do. You
don't have to create any of it because
the stack frame uh component has it
already. Now, the only thing I wanted to
also add here is some sort of link to go
home. So, uh I'll put here go back home.
Something like that. You can be more
specific. This is just so that we have
access to it right now. Um and I'll
write a link. I'll make an href to the
homepage.
And this should be good to go. If I
click here, we should be able to go back
home and then go to the sign-in page.
Now immediately you notice that this
page is completely black and that's not
good. The thing is if we open up our
globals.css there are a bunch of stuff
that comes with it. Now we're not really
going to be doing much with this
globals.css file. We're going to be
using Tailwind colors. We're going to be
uh, uh, you, know, we're, not, going to, be
using any custom colors or anything like
that or creating any utility classes.
This project is not going to have black
and white themes because I don't even
think it matters for a project like
this. So I'm just going to delete all of
that. I'm going to leave it like this.
And this should be fine for the globals.
CSS. Now, another thing I want to do is
I just want to add some color to this
page. I want to make it be the same uh
background color as we have over here.
So, to do that, I'm going to add here a
BG gradient
to BR. This is going to make it such
that we can make a gradient from the
color purple 50, which is very very like
it's not it's barely purple. So it's
just white and purple to the color
purple 100. So if you're not familiar
with making gradients in Tailwind CSS
this is how we would do it. And you can
see a slight gradient here at the
bottom. Now the next thing is I want to
add a class name to this div. We're
going to set it to be a max width of MD.
We're also going to set the width to be
full and we'll set a space in the Y
direction to be eight. So you'll see
this will now have a little bit more
space in between each other. Now you can
see we have a beautiful sign-in
component also because it created the
loading.tsx over here. Uh the loading
for all of these components are shown.
So if I refresh the page, you see
there's a loading state for this
component. So it's pretty cool. Um okay
great. Now we have this. Does it
actually work? Well, let's test it out.
I'm going to sign in with GitHub. I'm
going to click over here.
It's going to ask if my GitHub account
authorizes it. I'm going to click
authorize. And let's open this up. Let's
see what happens. Great. I'm back in the
homepage. But did it actually work?
Well, there's one way we can know. If I
go to the signin page, what happens? Oh
I put sign in incorrectly. It has to be
like this.
Well, it says you are already signed in.
Sign out. that state is already handled
by stack frame. Now the real way to know
if it worked if is if we go to neon over
here and we go to the off for users. You
see that now there is a Pedro Marshado
user that joined on September 21st, 2025
at 4:13 p.m. So you can see all of your
recent signups and all of your user
information over here. Great. That was
pretty easy. We basically didn't have to
do anything. Um, and it we're here now
that the user is able to sign up, let's
start creating the state of the app
where the user can see a full dashboard
with a sidebar, their inventory, and so
on. So, in order to do that, the first
thing we need to do is we need to create
the data that is going to fuel all of
those routes. So, we can't see a
dashboard if there's no data in the
database table. We can't add a product
if there isn't a product table. Same
thing with all of the other routes. So
what we want to do is we want to go back
to where we left off with Prisma and we
want to create the Prisma model that is
going to represent our table. So in
order to create a model on Prisma, it's
actually pretty simple. These two things
that are over here, if you're not
familiar with Prisma, they're just for
configuration. They just link our URL
for our database, the one we have in our
environment variables. And also uh
there's an output if you want to um
output your types into a specific
folder. You can keep this. I like to
just delete it so I don't have to worry
about that. So you can delete that as
well. Now below here, what we can do is
we can define our table. To define our
table, we create a model and we give it
a name. So in this project, we have
products and each product will have
certain fields. The first field it's
going to have is an ID. And an ID to
this to to define its type in Prisma
you just give the type right next to it.
So it's a string. And specifically for
an ID, we give this to um decorators to
it, this to properties to it so that it
knows that it's an ID, right? So you
give the ID property and you also
specify that you don't have to actually
pass an ID whenever you create a
product. You can just default it to call
this CUID function that will assign a
UID to that field. Now the other ones
are going to be simpler. The second
field we want is a user ID. Now what is
a user ID? is just the ID of the user
who created this product.
So in this case, we're going to assign
the stack of user ID of the user we just
created. So if I go back here into the
Neon console, you see I was created. If
I click this view details, you see that
I was assigned a user ID. That's what's
going to be part of that type. Now let's
go back here. The next thing we need on
a product is we need a product name. A
product name is just the name of the
product, self-explanatory, and it's
going to, be, a, string., The, next, thing, is
an SKU, RSQ. It is basically a number
that is unique and it's kind of internal
so that retail companies can um keep
track of their products. So, it's it's
each product has a unique identifier and
that's what this Q means. Now, since
we're not really a company, I don't like
I don't really care about this. Uh I'm
going to make it optional. So I'm going
to make a string that is optional. But
one thing we want to enforce is that if
you have a if you pass a skew then it
has to be unique. Now the next thing we
want is a price. A price can be a number
but it's better to define it as a
decimal because we can also put prices
with like with cents, right? And we want
to specify what kind of price this
means, right? Because there's no such
thing as something that is 2.8586. 8586
right? It only goes to two decimal
places. So the way we do this to enforce
this in Prisma is by adding the db
decimal property over here.
This allows us to specify by adding 12
and two that we only want up to two
decimal places. Now down here, we want
to specify also that we want to know the
quantity of the items. Quantity is going
to be an int. it's not a decimal. And if
you don't put a quantity, it's going to
default to zero.
Now, we also want to keep track of if
the the product is actually considered
to be low stock. And that might change
depending on the product. So, if you
think about it, a like if you're a a
company selling tractors, right?
uh it's not considered to be low stock
if you have a 100 tractors because
they're huge and they cost a lot and you
it takes a while to sell them. But if
you have a chocolate bar and you only
have a hundred left, that should be gone
in a day or two. So that's a different
uh low stock property to it, right? For
a chocolate, the low stock uh status is
given at a much higher quantity uh than
for some for for example for a tractor.
So what we want to keep track is what
number is this product considered to be
at a low stock. So I'm going to make a
low stock at pass an integer and this is
optional but it's good to pass it as
well so that we can keep track of them.
The last two that we want to add are
properties that I think you should add
to every table you create. The first one
is the created at and that's going to be
of type daytime and it's just whenever
you add this product to the table uh
when was this product added and you can
actually do that automatically. You can
pass a default property and call the now
function and it will automatically add
that. You don't need to pass that value
to your um whenever you add data to your
database table. And the last one is the
updated at field which is again a date
time and you can give this updated at um
decorator that will just basically u
fill this up every time you update a row
in the database table. Now there's only
two more things we want to do here and
this is a bit more advanced but you when
we get to the point I'll be able to
explain it better. What we want to do is
we want to create a composite database
index on our table. This will make it
such that there's an index to two
columns together which whenever we need
to query information from this database
table, it will make it actually faster
to filter and sorting whenever we do
that. So we want to do it for two actual
uh columns together. So to create one
you just create an index. you pass an
array and the two columns we want is a
user ID and a name and we also want to
create another index but this one is not
a composite one we only want to create
it for one column it's the created at
column so this should make it such that
we are able to create our database table
and um save the information about the
products so now that we defined this how
do we send that to here right how do we
send that to the neon console so that we
can see it in our tables over here.
Well, to do that, it's pretty simple.
What I want to do is I want to open up
the terminal again. I want to clear this
terminal so you guys can see everything
better. Then I want to run npx prisma
migrate, which will migrate the model
you have here from your schema to the uh
to wherever your database is being
hosted. Then we want to say dev, which
will make it let us let it know that we
are currently in development. And we
want to give a name to this migration.
I'm just going to call it init because
it is the initial migration we're
making. When I press enter, since we
connected our database table correctly
this should create the table in our uh
console. So you see it seems to have
worked. It is running a generate command
which will generate types for um our our
model so that we can have uh type
definitions to the product model. And it
seems to be successful. If I come over
here and I refresh this, we should see
the table now over here. Now we see two
tables. The first one is the Prisma
migrations. Every time you make a
migration, it will add a new row to this
table. And that's fine. You don't have
to worry about it. You don't even need
to look at it. It just saves that
information, which is good for uh
tracking. The second one is the product
which is the one we really care. And you
can see all of the columns that we
wanted are over here. Perfect. It's in
perfect position for us to start adding
data to it. Now, how are we going to add
data to this table? There's multiple
ways., We're, going to, have, an, add, product
uh like route, and that's great. We're
going to do that. But for the meantime
I actually want to add some fake data to
our database so that we can test it. So
we can use it for creating the other
routes that require data uh and not have
to create everything manually. Now to do
that you can create what is known as a
seed file. Now a seed file is a file you
create in uh for your database tables
and it se it seeds the table. It inserts
that initial um data into your table
that maybe you're going to be using for
testing but you're bypassing having to
do it through your own website. So to do
that we're going to click here on uh the
Prisma folder. I'm going to create a
seed.ts.
This is going to be a um JavaScript file
that will contain the logic to adding uh
uh the new products to our table. Now
how do we do this? Well, the first thing
we need to do is we need to import
Prisma client
from Prisma-client.
This is going to give us the access to
the
Prisma variable that we can use to
access our tables. Now with this we can
create a function that will be executed
when we run this seed script. We're
going to call it main. And in here we
want to basically write logic that will
create a bunch of products, random
products for a specific user. Now I
specifically want to create products for
the user account that I just signed
into. So if I go here to O, I want to
create that so that we can see that
data. So I'm actually going to copy here
view details. I'm going to copy the user
ID and I'm going to create here a
variable called uh demo user ID. I don't
know. And I'm setting it equal to this.
Now, we want to write some logic such
that this script is going to add a bunch
of items into our products table. Now
to do that, I have this script over
here. I don't want to manually write it
again because uh we're going to go over
uh using Prisma and adding stuff to the
table when we get to that part. We're
just doing this first so that we have
some data. What this does is very
simple. It uses the Prisma variable
right the Prisma client to access the
product model and it calls the create
menu function. The create menu function
is a function used to insert more than
one entries into a table in your
Postgress SQL database. Now we have here
we specify that we want to do that to
the product table and in here we pass an
object with a data. Now in this data it
takes in an array of objects uh that
represent a product. So you see all this
is doing is it's creating an array with
25 items. That's the amount of products
I want to add in the beginning. And for
each of those products, it's creating a
product that is very simple. The user
who created the product is me. It's the
user ID put over here. The name of the
product is going to be very simple. It's
going to, be, product, 1, 2, 3, 4, 5., So, we
don't get confused. The price is just
random. The quantity is random. And the
low stock I just added five to all of
them, but we can obviously change that.
and the created at I specifically wanted
to make them random. So it's a random
value um it's like it changes for each
thing so that uh we can test how it
looks when products were creating at
different parts of or different times.
Now I highly recommend that you run the
same script so that you get the same
kind of data as I do. Now the next thing
we want to do is we just want to come
here and call the main function. We're
going to catch any errors that happens
and if nothing happens, either we catch
it or it's successful, we're just going
to disconnect the Prisma table. That's
what usually happens when you have a
seating script. I also just want to put
a console log over here so that we know
that the script was successful and we
should be good to go. So now that we
have our script created, we can run it.
I'm going to come over here and I'm
going to clear this up. I'm going to say
node and then I want to go directly into
where this uh file is. So it's in the
Prisma. So I'm going to say prisma
slash seed.ts.
If I run this, it should execute the
script. So if I press enter, you see it
says seed data created successfully
created 25 products with the user ID and
the user ID that I put. Now let's test
this out. Let's see if it actually did.
If I go over here and I refresh the
table, we should see 25 products each
with a different price, different
quantity, and they were created at
different times. So now we have some
data. Whenever we start building the
front end, we're going to be able to do
it. Now to start building the dashboard
UI, we have to create the component that
is going to serve as the sidebar. So
we're going to start over here with um
coming to our project. We're going to go
to the folders over here and we're going
to create first the page.tsx that is
going to render the dashboard. Now here
I'm going to export default function
called
dashboard page and I'm just going to
return a div for now that says
dashboard. That's all I want because I'm
just creating this for us to be able to
start structuring our sidebar. To create
the sidebar, I want to create a folder
called components. Now, in the
components folder, I want to create the
components that don't really fit with
the pages. For example, the sidebar
component is a good example of that.
Now, the sidebar component is going to
be like a navbar, but it's on the side
obviously by the name. And we're going
to export default a function called
sidebar. Now, for the sidebar, we're
going to have some props. More
specifically, we're going to take in the
current path as a prop. By default, the
current path of the user is going to be
the dashboard. And that's going to be
used to be able to distinguish like show
which uh p like where in the navbar we
are in. So you guys will see what this
means. We're going to put a different uh
collar to the route that we're in so
that it is easy to know. Now we're going
to put the type of this to be an object
which takes in a current path which is a
string. Now in this sidebar we want to
return a div. And this div is going to
be of class fixed because the sidebar is
always fixed on the left. We're going to
set the sidebar to start at the left
zero and top zero. So it starts at the
top left. The background of it is going
to be gray 900. That's the color. and
the text inside of it is going to be
white. Now, we want to set a sidebar
width. You can choose whatever you want.
I usually like to have a small sidebar.
So, I'm going to set it to be 64. Now
the height is the full height of the
screen. So, I'm going to set it to be
the minimum height of the screen. And
I'm going to set there to be a padding
of six on all directions. And I'm also
setting the Z of it, the Z-index to 10.
Now, if we go here, nothing really
shows. If I go to the dashboard page, we
just see dashboard, but we don't see the
sidebar. What I want to do instead is I
want to put the sidebar into every
single page that will require it. So in
here with the dashboard page, we'll
start by making this just be also the
height of the screen so that it's the
entire page. And we're just going to set
as a simple gray 50. I don't want to
have a color of white on on this. I
think gray 50 is better. And then what I
want to do is the first thing I call
here is the sidebar component that we
just created. I'm going to pass the
current path to be slash dashboard
because this is the dashboard page even
though by default we are setting to to
slash dashboard as well. Now you should
see that we should see the sidebar
appearing just how we defined it. Now
I'll pull this a bit like this so you
guys can see uh the UI as we write it.
But the next thing we want to do is we
want to set the logo of uh the website.
Now I don't have an logo image for this
website, but if you do want to create
one, you can make one look really cool.
I'm just going to be using an icon for
this. So to do this, I'm going to create
a div. And this div is going to have a
class name of margin bottom of eight. So
there's a distance in between the logo
section and the other sections over
here. This should appear up here.
Then we'll create a div
which is going to include uh it's going
to be a directional div. We're going to
say the display the display is equal to
flex. The items are going to be centered
and we're going to space all the items
in the x direction with two and set the
margin bottom to be four. Then I want to
set another div. This will be to create
the icon of the website. Then I want to
put the icon of the website. Now for the
icon of the website I want to be using I
will be using Lucid React for icons. Now
you can use whatever icon library you
want. If you want to use the same one as
I do, I'm going to install here npm
install Lucid React.
And this is going to install a bunch of
uh icons that we can use in our website.
For example, for the logo, I'm going to
be using the bar chart
3. That's the icon I want. Now I can
import this at the top over here. So I'm
going to import
from
Lucid React and I want to import the bar
chart 3. Now you see this is the icon
that shows up. Now for this I just want
to set a different size to it. I'll set
the w the width to be five and the
height to be five. So it's a little bit
smaller. Now for this I just want to set
a, different, size, to, it., So,, I'm, going to
set the width to be 10 and the height to
be 10. I think that should be good. And
then what I want to do is I want to add
a span with the title of the the
websites. So, you can call it whatever
you want. I'm going to call it inventory
app.
And
I'm going to set this to be a text
large and a font semibold. Now, to make
this actually appear next to it, just
realize we need to put this over here.
And we should be good to go as long as I
close this and delete this. Now, it
shows up over here. Now, obviously, you
can make it look whatever you want.
Actually, I'll make this a lot smaller.
Probably make it seven and seven.
That should make more sense. Yeah
that's good.
And yeah, that's it. So, that's the
title section. Then below this, we want
to start building the actual links. So
we'll start by creating a nav over here.
And with this nav, we're just going to
separate every item in it in the y
direction by one. Then inside of it, I
want to set a div, which is going to
have the name of the section for the
navbar. You can actually add more
sections to the sidebar. You can add an
inventory section, which is what all
that we're doing over here. But then you
can have a team section. I don't know
whatever you want to add to your
website. Now, for this uh divider
section divider, I'm just going to add
some styling to it. I'm setting the text
to be extra small. Then I'm going to set
the font to be semi bold. I'm going to
set the text to be gray 400. And I also
want to make it always be uppercase
so that it's like this. Now I do think
the text over here might be a bit too
small. Um if it is we can easily just
increase this to be uh small
and then it will be a bit bigger.
Perfect. Now below this what I want to
do is I want to render the links. Now to
render the links I want to create a list
called navigation.
And on this list, we're going to create
objects for each link in our sidebar
with some properties. For example, the
text that is displayed for the link. So
the first page we're going to have is a
dashboard. So I'll make that one. The
href for that link. Now the href is just
the route that the path name to that
route. So it's going to be the dashboard
route. And finally, an icon to represent
that, route., So, I'm, going to, put, here
icon. And for the dashboard, it's
actually going to be the same one as we
put over here. It's going to be bar
chart 3. Now, we want to create the same
thing but for all the other links. And I
have done that. So, these are the other
links. We just have to import the uh
icons. And what they are is we're
creating an inventory route with the
slashinventory route and we put this
icon the add product route with the add
product path name and the settings with
the settings path name. Now we want to
loop through that list right below this
inventory uh part over here. And for
each item that we loop through, we're
going to get the item and the key. And
for each of them, we want to render
a link.
Now, to get the information about it
we're actually going to make sure that
we wrap this around with a uh curly
braces, and we're just going to return
the UI down here. Now, make sure you do
add the actual parenthesis over here.
And it should kind of look like this.
Now, why do we need this? Well, first of
all,, in, the, link, that, we're, going to
add, we need to make sure we import the
link from next link. Then we're going to
set the href to be equal to the
item.href.
That's the link that it should take us
to. Then we want to put a key to this
item. The key is just going to be the
key from the map. And the label over
here is going to be uh the item.name.
So it should look a bit like this, but
it's obviously not well styled at all.
So what we want to do instead is we want
to add some class names to this link. So
I'm going to set the display to flex.
I'm going to set the items to center.
Then I want to set a space in the X
direction of three. Now why do we do
that? Because there's nothing really to
be spaced, right? Well, there actually
is. Inside of this link, we want to
render the item do icon.
And you see this doesn't allow us to do
it because the item icon is a component
and you can't render a component just
like this. So to do that, what we need
to do is we need to get that icon
component,
set it equal to item.
And render it as an actual component
just like this. and then we'll actually
be able to get those icons. Now, for
each of those icons, I'm going to set
the width to be five and the height to
be five. They're going to be a lot
smaller. Now, then instead of just
rendering the name like this, I'm
actually going to add a span so that I
can set the size of the text. For the
span,, I'm, going to, set, the, text, to
small. Then, what I want to do is I want
to continue here. I'm going to set the
padding in the Y direction to be two.
So, make everything a lot bigger and
spaced out. I also want to make it
rounded and I want to set it to be
rounded large. Now, why am I doing that?
You can't really see the border. But the
thing is, if the
path that you're in is the active one
so we're in the dashboard route. If we
are in the dashboard route, we actually
want to show that we are in the
dashboard route in the sidebar. So to do
that, we're going to get a boolean
telling us if this is the link for the
current active route. To do that, we get
the current path
of the prop. So the current path and ask
if that's equal to the item.href.
If it is, then this is true. And we can
change the styling based on that. So
we're going to use that boolean in the
class names over here.
We're going to change this from
quotation marks to back ticks because
then it allows us to insert some
JavaScript in here. And what we want to
do is we want to check to see if the is
active is true. And if it is, then I
want to set the background of the
section that that is active to be equal
to purple 100.
Also, I want to set the text to be gray
800. If it's not active, then I want to
set the text to be gray 300. And what
this will do is, as you can see, when
we're active on the dashboard, it shows
that if we weren't in the dashboard, we
don't have the other routes yet, it
would switch and show it over here. Now
there's obviously some stuff that we
want to change in here, like the fact
that there's no padding. So, to add the
padding,, we're, going to, add, here, a
padding x of three.
And it should look a lot better. Also
on the second one over here, I want to
add a hover to it. So, if you hover the
second one, we should change the
background to be gray 800 as the color.
So, you see as you're hovering, you can
click on them. Perfect. Now, we're
pretty much done with the sidebar. The
only thing we want to do left is below
the navbar. Actually, right here at the
bottom, uh let me just hide this. This
is part of Nex.js JS uh development
right here at the bottom we want to show
information about the user. Now to do
that what we want to do is we want to
get a div over here and fix that div at
the bottom. So to do that we're going to
set it to absolute bottom zero left zero
so it's at the bottom left. We're also
setting it to right zero and we're
setting a padding on all directions of
six with a border only at the top. Now
the border will have a color of gray
700. And after that we'll enter here and
I'll add another div which is going to
have a class name display of flex item
center and justify between.
Now inside of it we're going to be using
one of the coolest components from stack
frame or stack off. It is going to be
the user button component. Now, this
component allows us to display a button
with the information about the user. So
you see because I'm logged in with my
Google account or my GitHub account, it
has my profile picture from GitHub
already over here. If I click on it, you
see I can access information about the
user account like the user account
settings and it takes me to a page just
for that information. Now, we're going
to deal with that later, but you can
also sign out directly from here. Now, I
do want to show the user name and email
right next to this. And to do that, you
just add the prop show user info, and
it's going to automatically insert that
as well. Also, it's aware of spacing, so
it doesn't actually show the entire
email, which is pretty cool, too.
Now, we're pretty much done with setting
up the sidebar, and I think it's time
for me to open this up so that we have a
full view of the page. With this in
mind, let's close this up, and let's
continue building the dashboard. With
the dashboard, I want to start by adding
a main section that is going to
represent whatever is over here to the
right of the sidebar. So to do that, I'm
just going to set first a class name
that is going to have a margin uh left
not bottom, of 64 and a padding of 8.
Now, it has a margin left of 64 so that
we have some space in between the
outside of the sidebar. Now, inside of
this main, we're going to have a header.
So, I'll even notify here so you guys
can see it. We're going to have a header
that is going to have a div. And this
div is going to have another div inside
of it. And that other div is going to
have another div inside of it with an H1
tag with the title. Now, this is going
to be the structure of every header in
each page we have. So, I'll explain to
you guys what we're doing here. So
we'll have a header and a padded
paragraph tag, which is with the
description. We're going to write
something generic like, "Welcome back.
Here is an overview
of your inventory." Think about it. The
dashboard page is just the collection of
information about your inventory. It's
not your inventory itself. It should
just give you a stats and summarizations
of that kind of stuff. Now, to structure
this header, it's pretty much already
structured. It's in the place that we
want, but there's some minor things we
want to change. First, I'm going to set
the margin bottom of this whole thing to
be eight because we're going to put some
stuff below it. Then, we're going to add
here a class name. We're setting it to
display flax. We're going to center the
items. We're also going to justify in
between.
Then, inside of this dashboard H1, we're
going to have here a class name that is
going to be text to XL to make it
bigger. The font is going to be semibold
and we're setting the text to be gray
900.
Then on the paragraph over here, we're
going to set the class name to be text
small. The text will be gray 500. And
this is how it should look like. Now, if
we come back here
we're pretty much done with the header
section. We want to start building the
key mattress section. This is where if
you remember the demo, we had
information about how many items are out
of stock or or low stock, how many items
we have, the the price, all that kind of
stuff. But to do that, we need to have
access to that information. So what I
want to do is I want to come up here to
the top of this component and directly
in here, we want to query the
information necessary for this page. Now
for the dashboard page, remember it
should look a bit like this. So I just
open up the final project on a different
uh different uh code editor and I just
ran it and it should look a bit like
this. So in the key matrix it should
show information about the total amount
of products we have, the total value we
have and the amount of items that are
out of a low stock. So to get that
information, we need to make a query to
our database table. And not only that
but we need to find out three different
things. We need to find out the total
amount of products, the total value, and
the amount of items that are in low
stock. So let's start with only one.
Let's just get the total amount of
products. To do that, I can say const
total products.
Then I need to make this an async
function so that I can directly query my
database here. And I can set this equal
to await Prisma from Prisma client. But
actually this doesn't really work
because Prisma client is a the class
right. So we haven't actually set up a
variable an instance of the Prisma
client uh class that we can reuse on our
project. To do that we need to come into
our uh project over here and we want to
create a lib folder. I'll create a
folder over here. Let's call it lib. And
in, this, lib, folder, I'm, going to, create, a
new file called prisma.ts.
Now in this file I want you to paste the
following. This is code that I copied
directly from the Prisma documentation
and it's required for you to get Prisma
client to work in your project. This
should at the end export from this file
a Prisma variable that we can use
throughout our entire app to access and
edit our database. So in here we just
have to say Prisma and now import the
one from the file on the lib folder. Now
when we're quering for products, we need
to specify that we are quering for the
product table. So we specify that it's
the product table. Then I want to get
the count of the amount of products. So
to do that you can use the count
function. And the count function allows
you to pass in a object inside of it
specifying what you're trying to count
out of this product. If you just don't
put anything, it's just going to count
all of the products, which is kind of
what we want, right? So, if I were to
didn't put anything here, you see that
if I were to console.log
total products and I were to go back
over here, open up my inspect element
go to console. You see that we see 25.
So, we are correctly counting the amount
of items in our table because there are
25 items. But there's an issue. The
issue is that if another user creates 25
more items and we are just getting the
count of total products in this table
it's going to say 50 instead of 25. Even
though I only want to show the number of
total products that I have created
myself, right? This number should only
be for one user. So this is an issue. We
need to actually only count the total
amount of products that the user who's
logged in created. So to do that, we
need to get the ID of the user who is
logged in. And the easiest way to do
that is actually we're going to create a
file in our lib fold over here. I'm
going to call it o.ts. And the reason
why I'm creating a separate file is
because I will reuse this logic multiple
times. We're going to create a function
called get current user. And we're going
to reuse this multiple times. And get
current user is going to give us
information about the user who's
currently logged in. To get that
information, we can get it from
the stack server app uh from the
stack/server file and we just call the
get user function. Then since we're
going to reuse this multiple times, we
can handle what happens if there's no
user. If there's no user, we want to
forcefully redirect the user by using
the redirect function from next
navigation. and I want to redirect them
back into the sign in page.
Then if there is a user, we just return
them.
Now in this in the page.tsx
we want to try to query for that. We're
going to say const user is equal to
await get current user. And this should
give us back the user ID. I'm going to
make a variable called user ID which is
equal to user do id. And with this now
we can specify when we get the count of
the products that we only want to get
the products where the user ID of the
product is equal to the user ID of the
user logged in. So technically I can
even just do this. Uh I do need to wrap
this around within object. Now, when
you're working with Prisma, this wear
clause over here is super important.
What it does is it allows you to specify
conditions for what operation you're
trying to make. And here we're just
saying I want to count all the items in
the product model or the product table
where this field of that product table
is equal to something else, which is in
this case is the user ID. Now, if I
refresh this, it should still say 25
because there's only 25 items. So, uh
it doesn't really change, but if there
was more items created by other users
it should only show the items created by
the one who's logged in. Perfect. Now
we have the total products. What else do
we need? I want to know uh, how many
products are low stock.
So, how do I do this? Well, I'm going to
say await prisma.product
again. And I also want to count. Now
this one is a bit harder. We're still
going to count where the user ID
is equal to the user ID which again we
can just shorten this to become like
this. But now I actually want to check
to see if the user uh the product is at
a low stock or not. That is actually a
bit complicated and I
and we are going to eventually do that
but I feel like I want you guys to get
your toes a little bit more wet on uh
Prisma till we get to this point. So
let's actually leave it like that and go
to the next one. The next one is a
little bit easier but a little bit
harder than the total products. This
next one is going to be the recent
products. Now why do we even need to get
the recent products? Because if you look
over here, we are showing the stock
levels of the recent products. So, how
many units each product has. And to do
that, we want to go to Prisma again.
We're going to look for our products and
we're, going to, use, the, find, menu
function. The find menu function allows
us to query for multiple rows in the
table by specifying a condition. The
condition is I want to find the uh
products where the user ID is equal to
user ID meaning the ones I created but
then I only want to take five of them.
So don't give me all 25 only give me
five. And before that I also want to
order those items based on when they
were created. So I only get the most
recent ones. If I order it based on a
descending order I only get the five
most recent ones. You see that if I were
to console log this, I'll console log
the recent. That's exactly what we get.
If I were to come here, inspect element
we should get a list with five items.
And it should technically be the five
most recent ones. Perfect. Now, we have
um the recent amount, the total
products, and what else do we need?
We're going to leave this two over here
for later. we just need to calculate the
total price of all the products you
have. So to do that, what we need to do
is we need to get all of the products
and then calculate that price. Now I'm
going, to, come, over, here., I'm, going to
create a variable called all products.
I'm going to set this equal to await
prisma.product.find
many. The same thing we just did. But
now what I want to do is I want to
specify that I only want to get the the
same with the user ID
and I can specify that when I query all
the products I don't really need every
single piece of information about a
product. I'm only querying it so that I
can calculate the the the
total value over here and also I want to
know how much quantity of them I like I
have. So like to know the amount of
items that are in stock, low stock and
so on. So to do that, I can actually
specify that when I query for all of the
products that I have in this table, I'm
only getting certain columns. To do
that, you use the select
uh property. And you can specify which
columns you want to select by writing
the name of the column and then set
setting it to true. If you don't write
the column, it's going to be false. So
we want the price column, the quantity
column, and we want the created at
column. Then when we get all of them
back, we want to calculate the total
value of all of them. To calculate the
total value, we're going to use a simple
trick with some JavaScript functions. So
I'm going to call this the total value.
I'm going to set it equal to all
products. I'm going to call the reduce
function. Now the reduce function allows
us to pass two things, right, as an
argument, a sum, and we're going to get
each product from that that actual
array. And for each of them, we're going
to return the sum plus the price of the
product. So to do that, I'm getting the
number of the product.pric
and I'm multiplying that times the
amount of that product that I have. So I
do that by doing times number of product
do quantity. And since this is a reduce
function, we have to pass as well the
initial value which is zero. This should
go through each item in the all products
array. It should add the price of each
product times the quantity to the total
amount. And in the end, we should get a
value. I don't know what this value is
going to be, but let's check it out. Let
me console log. Apparently, it's 15,000
or 16,000 almost. So great, we are
getting the total value now.
And for now, this is enough. Let's use
the information that we just queried and
display it in our screen. So to build
the, UI,, we're, going to, come, down, here.
We're going to add a div.
And the this div is going to be a grid.
So I'm going to apply here a class name
of display grid. We're going to set the
amount of columns to be one, but in a
large, screen, and, above,, we're, going to
set it to be two because there's more
space. Then I want to set a gap between
them to be eight and a margin bottom to
be eight as well. Inside of this I want
to set another div. This one will have a
class name of bg white. I'm going to set
it to be rounded large have a border and
make it be border gray 200. This is
going to be each
of the different sections. We're going
to have four of them, right? But you see
here we have the border already set up.
I also want to put a padding of six. And
we see now it actually appears. It's
kind of very very light, but it's it's
the whole point of the UI. Then we're
going to set a H2 tag. This one we'll
say key matrix. On the key matrix, we're
going to put here a text large, a font
semibold, and a text gray 900, and a
margin bottom of six. So there's some
space. Then we're going to come down
here., We're, going to, set, another, div.
This one will be another gridlike
structure. So, we're setting a class
name of display grid. We're setting it
to grid calls three because there's
three stats that we want to show and a
gap in between of them of six. Remember
we don't have the stats for the low
stock, but we're just going to put a
random number for now. Then, when we
come down here, we're going to start
with the first. So, we're going to add a
div which is going to be centering the
text. Then another div with the
information about the total amount of
products. So, to do that, I'm just going
to put total products over here. And we
should see that number appearing. Now
we want to actually put more than just
that. We also want to put if this is a
change in the previous month. So to do
that, I'm going to put over here another
div that will say total products. Then
below this, I'm adding another div with
a span
that will say plus and then the amount
of total progress because this is how
many were changed in the last month or
so. And if it's trending up, I want to
put a trending
up icon. The trending up icon I can
import
from the Lucy React library and I can
import the trending up icon. Perfect.
And it should look a bit like this. Now
let's put some of the uh styles to this.
So for the total products I want to say
text 3XL
then a font bold and a text gray 900.
Then for the total products here, I want
to say
text small text gray 600. And then for
this one over here for the div that
contains the the change, we want to set
the display to flex the items center.
And we'll justify it to center and set a
margin top of one. Then for this pen
we're going to set it to be really small
because it's a number. And I want to
show the text to be green because it's
going up. For the trending up, I'll just
set a class name that will set it to be
width three, height three. And I'll make
the text or the icon also be green 600
and have a margin left of one. And it
should look a bit like this. Now, it's
not perfectly centered as it would over
here. So, there's definitely things that
we need to fix. For example, I realized
I didn't write text center over here and
that's why. Yeah, perfect. Now, we
finished the first section. I'm going to
copy this and we're going to create the
exact same thing two more times. Now
they are to the uh stacked on top of
each other instead of uh horizontal. So
we do need to fix that. Uh the reason is
I accidentally copied the wrong thing. I
apologize. You need to copy the div from
the tax center and below and then paste
that three times. Then you have uh the
three stats, but they're not the correct
stats. The middle one is going to be the
total value. To get the total value
we're, going to, get, the, total, value, over
here, but we're also going to uh it's
it's a decimal. So you'll see it looks
like this. We don't want to do that. We
want to show a full value. So what I'm
going to do is I'm going to convert this
into a number. And I want to fix it with
zero decimals. And then it will look
like this. Perfect. I also want to put a
money sign in front of it so that it
looks like it's money. Then I'll copy
this. And in the total product over
here, I'm going to add the same thing.
And I'll change the text here. So say
total value. Perfect. Now the last one
is the low stock. Remember, we haven't
done that yet. I feel like now we might
be ready to do it. So let me just
actually render the value that we have
there. And uh we'll go ahead and write
the correct value. So I'm going to put
here low stock. I'll put low stock here
as well. And I'll just change this to
say low stock. And again it should look
a bit like this. Now this number like I
said it's just using the same thing as
here. So to get the actual amount of low
stock items, here's what we need to do.
We need to fetch the count of products
for a user with the ID of the user
logged in. But then we need to put a
condition. We want to find to see if the
um low stock at quantity is not null.
Meaning that if we go over here
remember we made it such that the low
stock at is an integer, but it's also
optional. We don't have to put that when
we add items. So if that's not no
meaning that someone when you added the
product you made it such that it was uh
you passed the low stock at you want to
check to see if the quantity of the uh
product is less than or equal to the low
stock at so you use the LTE which means
less than or equal and you put a number
here which would be five by default.
And that will make it such that it
actually checks to see if it's low stock
and it finds that there's eight items
that fit that um criteria. Perfect. Now
one thing you can also do for this is
you see how we're getting three values
over here. We're making three queries
for them. We're making the query for the
total products, the one for the low
stock, and the one for the all products.
Now, all three of them should be for the
same purpose. Instead of making a
separate query each time like this, one
thing we can do is, by the way, let me
just take out this recent one that we
made and I'll pull it I'll put it below
this because we're going to use it in a
second. Right now, we're just focused on
this ones. What I could do is I could
actually come here, make an array, set
it equal to await promise.all
and then pass each of these queries as a
item in this array. Just like this. I'll
put first the total products, then I'll
put the one for the low stock, and then
I'll put the one for the total value.
Just like this. I'll make them each an
item of this array. And then depending
on which order we put them, this will
return an array with those items. So the
first item in this array is going to be
the value for the total products. The
second item is going to be for the low
stock and the third one is going to be
for the total value. And now with that
simple line of code, we can remove uh
this three queries. Uh I just realized
this shouldn't be called total value. It
should be called all products. And with
a promise that all we can do all of them
in one single operation without having
to worry. Perfect. Now we're done with
this section. Now what we're going to do
is this is the key metric section. It's
for the top, right? is for this top over
here. Uh the key matrix is actually
whatever is below here. This is for both
the key matrix plus the new products per
week. What we want to do now is do the
bottom row. So I'm going to copy the
same uh UI. I'm going to go below here
right where it finishes and I'm going to
add the other section. This one is the
one that goes down here. Now for this
one, we're going to start with the first
U item which is the one on the left.
It's the stock levels section. So, we're
doing this over here first. Now, for
this, I'm going to create a div. And I'm
going to set the class name to be BG
white. I'm going to set the rounded to
be large. I'm going to set a border.
We'll make it gray 200. And I'm setting
a padding of six.
Then, inside of here, I want to set a
div. And this div will have a class name
of display flex items center justify
between margin bottom of six.
Then inside of this I'm going to put an
H2. And this H2 is going to have stock
levels as the title. Now we're going to
put a class name here. We're just going
to set it to text large font semibold
text gray 900.
And it should look similar to what we
had above. Now below this
now below this div, we want to add
another div. This one is going to be
having a class name with a space y of
three. Now inside of here, I want to
loop through the list of recent products
that we queried before. It's five
products. And to loop through it, we're
just going to say recent map. We're
going to loop through each product. get
the key and for each of them we want to
return a div that will have some UI in
it. We'll pass the key
as the key that we have over here and
we'll start by creating a structure in
here that would fit the structure we
have above. Now the first thing we need
in this inside of this div is we need to
have a span that is going to have the
name of the product. So I'll just say
product.name.
Now all of our products have the same
name kind of. It's just a name of the
product plus a number. So you see this
is what shows up. The second thing we
need is we need a div for the units. Now
to make that I'm going to go outside of
this div that we created over here. I'm
going to make another div. And on this
one, I'm going to put the product
dotquantity
and I'm going to say units. And we'll
get the actual amount that of each
product that there is. Now, we want to
space them out. So, that one is over
here, the name and the uh number and the
quantity is on the right. Now, the color
actually is determined based on how much
in stock there is. So, if the product is
in low stock, for example, then it will
be yellow. If the product has no stock
it should be red. If the product has
good amount of stock, it should be
green., So, to, do, that,, I'm, going to, come
up here and I'm going to calculate the
stock, level., To, do, that,, I'm, going to
set it equal to the product do quantity.
I'm going to check to see if the product
do quantity is equal to zero. If it is
then stock level is going to be zero
which means that it has no stock.
If it's not zero, we're going to do
another calculation over here. If the
product do quantity is less than or
equal to the product dot low stock at
then it is in low stock low stock. So it
will be one. If not it will be two. But
here's the issue with this product of
low stock could possibly be null. Also
this should be replaced with a question
mark. Uh but yeah this could possibly be
null. So if this is null, so what we do
instead is we wrap this with a
parenthesis and we can check if this is
null, then we'll just set this to be
equal to five. And then this will check
to see if the product of quantity is
less than or equal to 5. So I know this
looks a bit complicated, but it's just a
bunch of if statements in in one single
line. All we're checking here is is the
product of quantity equal to zero? If it
is, we'll set the stock level to zero
which means there's no stock. If the
product has a low stock at uh property
to it, then is the quantity of the
product currently less than that? If
yes, then let's make the the item be at
low stock. And if there's no low stock
property, we'll just assume that low
stock means less than five. And if so
again, if the quantity is less than
five, we'll set it to one. If none of
that is true, it means that the you the
product has a lot of stock. So, it
becomes two. And that's the stock level.
Now, why do we even need to know the
stock level? Because we're going to
create some colors both uh of the
background. So, I'm going to call this
BG colors and of the text depending on
the stock level. So what we do is
the first item means stock level is
equal to zero meaning that there's no
stock for that. I'm setting the back row
to be red 600 and the text
to be red 600 as well.
Now I'll do the exact same thing for the
other ones but it will be yellow and
green.
And I'll be back when I write them.
Perfect. So we have BG red 600, BG
yellow 600, and BG green 600. And the
same thing for the text.
Then what I want to do is inside of
here, right before the name, I want to
add a self-closing div that is going to
be used to create this little circle
that we have over here. To make that
circle, all we do is we add a class name
in here.
Uh that will be a width of three and a
height of three. And then we're setting
it to be rounded full. And we need to
set a color. So we're going to insert
uh the BG color array. So we need to
replace this with back ticks and wrap it
with curly braces. And we want to insert
the BG colors and get whatever color the
stock level is. So if it's uh if it's
green, it should be green. All of them
apparently are green, but it would be
cooler if one of them wasn't. I can
actually change that. So, I go to
product one. I'm going to make the
quantity be one.
Save change. Now, if I go back here, you
should see that it's now yellow. If I
were to make, for example, product two
be at zero
then you should see that it's at zero
and it's red now. Perfect. So, this is
working. The next thing is showing the
text over here to be a different color.
So, I'm going to come over here. I'm
going to set a class name. And the class
name will have a uh back text over here.
We're going to set the text to be small
the font to be medium.
And I'm going to insert the text colors
and set it to be a stock level.
And we can get the text to have that
color. Now, to space everything out
here's what we want to do. On the top
div over here, we're going to set the
display to flex, the items to center
and we're going to justify everything in
between. Then, I'm setting a padding of
three, and I'm rounding everything as
large, and setting a bg gray of 50. Now
for this inner div, we're setting a
display of flex. We're setting the items
to center, and a space in the x
direction of three.
Now finally on this span over here we're
just going to add simple classes like a
text extra small or it's just small
actually a font of medium and a text
gray 900.
And now you'll see that we have this
whole section created just like we had
over here. And now we have half of our
dashboard done. Uh we're almost done
with the rest. Now, let's start working
on the top right grid, which would be
this grid over here. It's going to be
the one that shows the chart. And in
order to make a chart like this, you
have to be using a chart library. Now
the one we're going to be using in this
video is recharts. To actually start up
this uh part of the grid, we're going to
go above over here, go down four divs.
So, 1 2 3 four. And then over here we're
gonna choose we're going to write
inventory over time. So what we're
trying to track here is
I'm going to track how many products do
we have per week or how many products
were added at each week. Now to do this
what we need is
we need first to create a div over here
that is going to set up the grid like
structure. So I'm going to say BG white.
It's going to be rounded large. It's
going to have a border and that border
is going to be of color gray 200 and
have a padding of six. Then inside of
here, we're going to make another div.
This one is going to be display flex.
I'm going to center the items and I'm
going to justify them in between. Now
the margin bottom is going to be six.
And, inside, of, this, div,, we're, going to
put a title for this section. We're
going to call it new products.
Uh actually I'll just do it lower case.
So new products per week.
Great. Then below this uh but outside of
this div, we're going to create another
div. And this div is where we put the
actual chart. I'm going to make a
certain height for this uh section.
We're going to be make it fixed at a
height of 48. And inside of here, we're
going to call this component we're going
to create called products chart. Now
why are we making a component and not
just doing the logic here? Well, to
utilize many of the chart libraries out
there, you need to actually be inside of
a client component. And when you're
building your app in XJS, it is
essential that you keep abstracting it
to a level that you only keep client
code on client components and only when
necessary. So this product chart
component that we're going to uh create
uh we're going to come over here and
we're, going to, go, to, the, components
folder and we're going to create the
products
chart.tsx.
For now we're just going to export
default function
and we're going to export the products
chart component which will just return a
div for now. Now this component is going
to have a prop. Now what is this prop?
It's going to be the data that is going
to be represented in this um
in this chart. Now this data is going to
be of type
chart data. Now we don't have that type.
It's an array that we're going to create
over here. We're going to define an
interface called chart data. And if we
think about it, what are we trying to
represent here? We're trying to
represent how many products were added
per week. So the chart data will be an
object that has the y and the x-axis. On
the, x-axis,, we're, going to, get, the, week,
which is going to be a string. On the
y-axis, we're going to get the count of
the products. So I'll put products, and
that will be a number. And that's the
data we want to pass to this component.
But we're passing it as props because
the data is something that we get from
here., Now,, we're, going to, import, this
component and we're going to pass the
product or the data directly here. Now
how do we get that data? Now, in order
to generate the data, we're going to
come up here and we're going to go above
the recent uh value that we have over
here and we want to generate an array
which is going to contain the same
format of how we structured our data
here. It's going to have a week and it's
going to have the products. So to do
that, we'll create the weekly products
data because what it's going to do is
it's going to generate the weekly
products data for however many weeks we
want. I want to specifically generate it
for the last 12 weeks. So what I'm going
to say is I'm going to say for let I
equal to 11. I is greater than or equal
to zero I -. So what I'm doing here
obviously because it's 12 weeks we set I
to 11 and we're just going in reverse.
Now why are we going reverse? So that we
have it uh up to date and the most
recent appearing first. Now we're going
to start here and we're going to say
const week start set this equal to new
date and then up here we're going to
create a value for now. So I'm going to
say const
now is equal to new date. And then I'm
just going to pass now over here. Then
what I want to do is I want to set the
start date for the week start. So the
start date inside of this loop is going
to be the week start the current date
minus its position in the array times 7
for seven days of the week. Then we want
to set the hours. And the hours we're
just going to say uh set it to 0 0. So
we're going to say set hours. So, that's
the, start., So,, we'll, set, a, zero, 0, 0 0.
Great. Now, we did this for the week
start so that we get where which part of
the week uh we're actually going to
calculate the data for. And then we're
going to say week end. To do that, we're
going to set and now the date to be the
week start date, not the uh now because
it starts at the week start. And then we
get the weekend
and we get the weekend over here as
well. But instead of subtracting I, all
we do is we just add six to it because
there's seven days. So we add six to one
day. Then the hours it's not 0 0 because
it's the weekend. So the last hour of
the day, it's obviously 23
hours, 59 minutes, 59 seconds, and 999
milliseconds. Then still inside of this
we're going to create the label. So the
week label is going to be the label for
what we're going to show on the um on
the actual graph. So, what I want to do
is I want to set this equal to a string
template because we're going to be using
some variables here. And I want to turn
the
following value into a string. I'm going
to get the date for the week start get
month.
And we add one to it because the months
are actually like an array. They are
zerobased. So we're just adding one to
get the actual month because if not then
July which is seven the month seven
right would be represented as six. So
that's all why we're doing this and
we're going to call the function pad
start. So we're going to say pad start
and what this will do is it will ensure
that it's always going to be two digits.
So for example, if the month is July
that's seven. But instead of saying
seven, we're going to pad start make it
two digits and the beginning we're going
to add zero to it. So that if it's not
already two digits, it starts with a
zero and it has two digits as its
amount. Now we'll start with this, but
then this is just a month. What we need
to do now is put a like a slash and add
the same thing, but for the uh week
dates. So, what I'm going to do is I'm
going to still use the week start uh
just like this, but we're going to get
the date.
And when we get the date, we're still
going to pad start to zero and we're
going to, get, the, labels., So,, this, will
give us these labels over here. Now, we
need to get the values for the product.
And we've created this whole uh time
frame over here because this is what we
need to use to create both the label and
the products. To create the products
though, we will create a array called
weak products.
We'll set a SQL. We're going to get all
the products that we have and we're
actually not going to make another
request. We're just going to filter
through them. And for each product that
we have on our table, we are going to
get the product date. We just want to
calculate. We have all the the weeks
that we are dividing our data for. We
just want to see which products were
created on those weeks. So, we'll get
the product date, which is just the date
of when the product was created.
And we're going to return this filtering
based on if the product date is greater
than or equal to the week start. But not
only that, we also need to make sure
that the product date is less than or
equal to the week end so that it's
perfectly in between this specific uh
group that we're showing in our chart.
And with this we have this array and we
can actually add this label this point
in our data to our weekly products data.
So I'll just push and it will look like
this. It will have a weak value which is
going to be the weak label and it's
going to have the products which is
going to be the weak products but we we
want a number and this this has the real
product information. So we just want to
get the length. Perfect. So now with
this we can pass this value over here
the weekly products data into our
products chart data. Great. Now let's
make sure that we actually we're
actually getting this as a correct
thing. So, I'm going to say console log
data and let's check to see. I just
refreshed over here. We're going to open
up the console log. And look at this. We
get two console logs. This, I think, is
just left over from the total value
console log. But the other one, it's an
array of 12 items that has each of them
has a date, like a month and a date, and
it's every seven days, as you can see
and it it shows the amount of products
that were added on those dates. Now, all
we want to do is display that
information in a way that will be
visible and look really nice on the
chart.
Now, like I said before, we're going to
be using a library to get this to work.
So, I'm going to come over here. I'm
going to close this up. And we're going
to run the following command. We're
going to run npm install
recharts.
And recharts is a very popular charting
library, one of the best ones out there.
And to use it, it's pretty simple. We're
going to come over here. We're going to
set a class name to this div. It's going
to be just a fixed height. We're going
to use 48 like we did before. And we're
going to set the width to full. Then
we're going to make this chart
responsive. So I'm going to use the
responsive
container from recharts. And to do it
you actually need to set a width and a
height. And I'm setting the width of to
be 100%. And the height to be the exact
same value. So I'll just say here height
is also 100%.
Then inside of this responsive
container, it needs a children. And
here's where you're going to choose what
kind of chart you want. There are a
bunch of different types of charts that
you can you can put. You can put a pie
chart, you can put um a bar chart
whatever you want. In our case, we want
to have a line chart that also shows the
area. Why show the area? So that it has
this little cool effect, the purple
color below the area of the lines. So to
do this, we're going to call here the
area chart from recharts.
Now inside of an area chart, we need to
pass some data. The good thing is we
already organized our data and we
already passed it as our props. So
that's great. Now the second thing is
I'm just going to apply some minor uh
styles to it. If I come over here, uh
it's giving us some issues, but it's
because we still have to put some stuff
inside of it. But I'm going to put here
just a couple styles. I'm going to set a
margin. Uh for the margin, we're going
to set the top margin to be five, the
right margin to be 30, the left one
should be 20, and the bottom should be
five. Now, these numbers might seem
arbitrary to you. It's just because this
is what I chose to make it look good
when I was building it. But you can
choose it. You can actually play around
with these numbers and see what you
think the chart will look better as.
Now, inside of here, we're going to
first put a cartisian grid. What is a
cartisian grid? is for us to see this
like it's barely visible but it's like a
a grid a grid that you can see on the
chart. So to do that we're just going to
add a cartisian
grid over here and you can choose how
this looks. So you can choose the stroke
dash array and in this case we're going
to put 33
and the stroke is just the color of the
lines. So, um, the color I'm going to
put is going to be f0 f0 f0 so that it's
not that visible. But, uh, huh, we're
still seeing an issue. Oh, yeah. Of
course, this issue is because we need to
turn this component into a client
component. So, we're using uh the
rechart library that is a client
library. And to get it to work, we do
need to turn it into a client component.
So, we kind of see the chart already
over here, but it's not that visible yet
because we haven't actually put the
data. Because to put the data, the most
important thing we need is to define
what the x-axis and the y-axis will look
like. Let's start with the xaxis.
The x-axis is going to have the
following data key. The data key is just
what it's the what is it going to be the
label for this axis and it's going to be
weak. The second thing is what is the
stroke of this axis? I'm going to put
666 as the color, which is uh gray. Then
you can put other customizations like
the font size, which I'm going to put to
12. You can also make it have a tick
line, which I don't want it, so I'm
going to, set, it, to, false., And, you, can
also put an axis line, which again, I
don't want it, so I'll put it to false.
And uh now we can see the x-axis with
the months appearing. But obviously we
have no uh lines because to make a line
you have to have a y-axis as well. So
what, I'm, going, to, do, is, I'm, going to
copy this and I'm just going to paste it
over here. I'm going to change this to
yaxis. And we should be able to update
this, import., Now, I'm, going to, remove, the
data key from here. We don't need it.
And one thing we also want since the
y-axis is going to be a number uh we
don't want to show any decimals. So what
I want to do is I want to say allow
decimals to false. Now uh based on how
we calculated the data, it shouldn't
have decimals because we just got the
length of an array. However, still it's
important for me to just prohibit that
from happening. Now the next thing we
need here is since this is an area
chart, we need to define what the area
is going to look like. Again, the area
is just what appears below the graph. So
I'm going to define this area and
there's a couple different uh properties
that I want to pass. The first one is I
want to pass a type. I'm going to set it
to monotone. The second one is we want
to pass a data key. And the data key for
the area is going to be similar to what
we put for the x-axis, but for the
y-axis. And since this is an area chart
we don't put that on the y-axis. We put
it in the area. The area is going to be
for the amount of products. Now, if you
see, we can get a correct amount. It's a
shame that they are actually all of them
are one. But if we were to come over
here and maybe change I'll change the
date here for this to be exactly the
same. If I do that maybe one of them
will be two. Let me see. Yeah. Now you
see that there is a bump over here. Uh
that's the thing with randomized data.
Sometimes it's it's not that random.
This one over here that I made is
actually perfectly random. But I will
actually randomize a bit more of this
data. uh just so that we have a better
sample size and I'll be back in a
second. Okay, I played around with the
data and this is what I got. As you can
see, it's slightly uh similar to what we
have over here, but there's some styling
that we still need to do. So, what do we
want to put? Well, let's come to this
area and we want to define a stroke for
the area. So, the stroke is just again
the color and right now it's blue, but
we want to set it to a bit of a purple.
And I chose this color over here which
is going to be again that purple that we
want. Now it's going to define the line
that is around it. But to define the
actual color of the area we have to put
a fill. And the fill is going to be the
same color
just like this. And you see now that if
I were to refresh this or just just look
at this it will be purple as well. Now
below this, I'm going to pass a fill
opacity. I'm going to set it to 0.2.
Then, I want to put a stroke width.
And this, it's up to preference. I'm
going to, put, it, two., Some, people, like, it
to be a little bit more thin. So, you
choose whatever size of the stroke you
want. Now, the next thing is I'm going
to pass a dot. And the dot I'm going to
pass over here to be I'm going to fill
the dot. And I want to make it purple
just as how we had on the the line. And
also I want to make the dot have a
stroke width of two and a radius of
four. Now you can remove this stroke
width if you want to and it would look
like this. Uh but that's a preference
from like whoever wants. You can make
this be smaller as well. You can make it
be like this. And some people like it
like this as well. Now the other thing
is the active dot. The active dot is
similar to the dot but it's for whatever
you're hovering over. Now what I want to
do is I want to set the radius to be uh
a little bit bigger. So four in this
case and uh just so that it becomes a
bit bigger when you hover it. Now the
next thing we need is the tool tip. And
the tool tip is just going to be what
happens as you're hovering it. So I'm
going to put here a tool tip uh from
recharts. And for the tool tip I'll just
paste here some of the styles that I
think matter. Uh, all we're doing is I
just want to make it such that when you
hover it, this thing appears. And it's
pretty simple. You just add some styles
over here. You put a content styled. You
put how that little tool tip is going to
look like. So, I made the background be
white together with the border being
right. And I put a little bit of a style
around it. So, like there's a little
shadow, which I highly recommend you do.
And then you put the color of the text
that is actually inside. Now, in our
case, it is showing something like this.
It says product one and the date. Now
we're pretty much done with the chart.
So I'm going to close this up and we are
almost done with this page. The last
thing we need to do is just add the
efficiency bar chart down here at the
bottom. So to do that, we're going to
come back to where we have our dashboard
page and we're going to go down to uh
where we have here quantity product
quantities units. We're going to go down
two divs below this. We're going to add
the efficiency
section. Now, in the efficiency section
we're going to add a div. And this div
is going to have a class name. I'm going
to set it to bg white. Setting it to
rounded large. I'm going to set a border
to it. Also, a border gray 200 and a
padding of six. Now, inside of this div
we're adding another div. This one will
have a flex as a display. I'm going to
center the items just to find them in
between. I'm setting a margin bottom of
six. Now, the first thing we're going to
do is add a title. It's going to say
efficiency.
For this title, we're going to add a
class, name., It's, going to, be, text, large,
font semibold, and a text gray 900.
Then, I'm going to get out of this div
and we're going to create another div in
here. This div, we're going to add a
class name that is going to be display
flex, item, center., and, we're, going to
justify center.
Then inside of here, we're going to add
something that has a position of
relative. So I'll say position relative
and, we're, going to, set, the, width, to, be
48 and the height to be 48. Now, what
are we adding in here? Well, if you look
over here, you might think that this is
a chart, but actually this isn't a
chart. This is a normal Tailwind CSS
with some HTML. Now, I don't want to
bore you guys with how you build this
specifically. So, what I want you guys
to do is I want you guys to just copy
what, I'm, going to, paste, right, here., This
is going to create that polygon and it
is going to add a percentage in stock.
Now, we don't have that percentage yet.
This is just manually written. So, you
see we see here the percentage of what
is this is in stock. Now to get the real
value here, we're going to come up here
right above where we calculated the data
for the first chart and we're going to
first try to calculate for the
percentage or the amount of products
that are in stock. So to do that, we're
going to create a variable called in
stock. We're going to set this equal to
all products. And we're going to use the
filter function to filter for each
product and compare if the quantity of
the product which we can get by
converting the P do. Quantity to a
number if that's greater than five. Why?
Because if the quantity is greater than
five, that's what we determine to be
what we consider that it is in stock for
a product. We'll calculate that. And
from the filtered function, we're going
to get the length and that's going to
give us the number of in stock items.
Then we're going to copy this. We're
going to paste it again. We're going to
change this to calculate. Now, for the
low stock count, uh I can also change
this to instock count. Now, in the low
stock count, we're going to do kind of
the same thing, but instead of greater
than five, we're looking for it to be
less than or equal to five. And also we
want to make sure that it's not out of
stock, completely out of stock. So we're
going to make sure that the quantity is
also greater than or equal to one. Now
why is it giving us an error? Because
for a second I thought it was Python. Uh
but we need to put a double amper here.
Perfect. Now this getting the length
will give us the count for the low
stock. And finally the easiest one as
well is the out of stock because out of
stock it's literally we calculate if out
of stock count and we calculate if the
number quantity is equal to zero. So for
the length of the array of only uh zero
quantity products that will give us the
count. Now we have the count. How do we
calculate the percentage? That's pretty
easy. We will first calculate for the in
stock. So, I'm going to calculate
instock, percentage., We're, going to, set
this equal to total products. And we're
going to check to see if the total
products are greater than zero. Why?
Because to calculate percentage, you
need to assume, right, that the the
denominator is going to have a value
greater than zero. So, or that it isn't
zero. And in our case, if it is not
greater than zero, we always assume that
the percentage is zero. But if it is
greater than zero, so we put a question
mark here. We're going to do the
following calculation. We're going to
get the in stock count and we're going
to divide it by the total products and
we're going to times that times 100, but
that can give us a decimal. And it's
expected that it will. So what we need
to do is we need to round that value by
using the math round function. Perfect.
That gives us in stock. Now for the
other, two, we're, going to, do, for, the
total stock uh the the low stock and the
out of stock. So low stock percentage
and
out of stock percentage. For the low
stock exactly the same thing but we use
the low stock count. And for the out of
stock also the same thing.
Perfect. Now we have all three
percentages and we're ready to actually
use those values. The one that is
important is the in stock for the the
actual efficiency one, right? The
circle. But we are actually going to use
all three of them in this little label
section at the bottom. So to do this
what I need to do is replace this value.
So instead of saying 67, which is
hardcoded, we're just going to show the
in stock percentage, which should be uh
60. No, it's around 60. Yeah, perfect.
Now, let's continue building the the
section so that we can build a legend
down here at the bottom. So, what I need
you guys to do is go to this in stock
part over here. Go down one, two, three
four divs. And below this, we're going
to add a div that is going to be a class
name of margin top of six. And I'm
setting a space in the y direction to
two. Then what I need to do is I'm going
to come over here. I'm setting a div.
And we want to set the display to flex.
We're going to center the items. We're
going to justify the items in between.
Set the text to small and the color to
gray 600. Now, inside of this div, we're
going to set the top, which is the first
uh set of percentages. This is going to
have a class name of flex
and then it's going to have item center
and we're going to space the two things
that are going to be inside of it with a
gap of two. Now, what are the two things
that are going to be inside of here? The
first one is going to be a self-closing
div which is going to represent a circle
for the in stock items. So how we're
going to create the self-closing div is
just a circle. We just set a width and a
height that is exactly the same because
that's going to be the radius of the
circle. We set the border radius to be
full and we set a background for the in
stock. We're setting the color purple to
200.
And we should be able to see that circle
now appearing at the bottom. Now we'll
put a text right next to it. And I'm
using spend so that there's no extra
styles to it. And I'm setting in stock.
And I'm just going to put the percentage
of instock percentage directly in here.
A percentage sign. And this should be
good to go. Now, it's giving us an
error, but I assume we can just refresh
this. And accidentally went to a
different page. Uh, but yeah, you see
here it says in stock 60%. Now, what
about the other ones? Well, to do the
other ones, all you need to do is copy
this three times. Now, the difference is
that on this ones, we're changing the
color from 200 to 600. And on the last
one is actually not going to be even
purple. It's going to be gray.
And we should have three circles now.
Now, why are they right next to each
other? That's because I made a mistake.
Actually, we need to copy this as well
for each of the divs or else this won't
work. So, I'm going to copy this div.
And I'm also going to do the same thing
over here
and
close the div. And now they should be
all on top of each other. Hm.
Interesting that they're not, but I
think it's because yeah, we accidentally
forgot to close the first section of the
div and we added an extra close over
here. Now it should actually show the
correct styling. Now we we're going to
change the values in here. The middle
one is going to be the low stock and
we're going to use the low stock
percentage as the value and the last one
is going to be out of stock and we're
going to use the out of stock
percentage. Now let's see if that makes
sense. It does because it adds up to
100. So we know for sure that it is
calculating the three different um
groups of products. Perfect. Now we're
finally done with our dashboard. All we
have to do now is build the other three
pages. Now the main one is going to be
the inventory page. This one is going to
have this beautiful uh table which is
going to show all of the items and it's
going to have some pageionation at the
bottom. Also, you're going to be able to
search for the items through this
filter. Now, how are we going to do
that? Well, let's go over here and let's
create the actual inventory page.
because right now if you go there
there's absolutely nothing. So to create
the inventory page we're just going to
go to the inventory folder and we're
going to create a page.csx. Then inside
of here we want to export
default async function and we're going
to export the inventory page component.
Now inside of this component we're going
to have some props. Right now we're
actually going to ignore those props and
we're going to start returning
some styles. So the first is going to be
what what creates the entire screen.
We're going to set the minimum height of
the screen to be equal to the height of
the screen. Then we're setting the
background to be gray 50. But what this
is going to do is it's not going to
include our sidebar. So to give the look
of our sidebar being permanent, we're
also going to include our sidebar over
here. Now remember the sidebar does have
a prop. So, we do need to put the
current path of this prop to be
slashinventory. So, when you're here
the sidebar knows where you are. So, if
you go to dashboard, you should see it
being uh white. If you go to inventory
we should be able to see it be white as
well, but we don't. Why? It's probably
because we misspelled this over here.
Perfect. Now, it actually works. Great.
Now that we added the the sidebar, let's
add the main section here. The main is
going to have a margin left with the
side of the with the size of the
sidebar., So,, it's, going to, be, 64., Then, a
padding of eight. Inside of this main
tag, we're going to first create the
header. So, we're going to create here a
div. It's going to have a margin bottom
of eight. Inside of this div, we're
going to create another div which is
going to have a class name of display
flex. We're setting the items to center
and we're going to justify
the items in between. Perfect. Then
we're just going to create an empty div
with an H1 tag that says inventory.
Now let's tile the inventory a bit. I'm
setting a class name to set the text to
be 2XL. The font is going to be
semibold.
And we're setting the text to be gray
900. Now, below this, we're setting a
description for this page. We're just
going to say manage your products and
track inventory levels. Something
generic like that. We're also styling
this, text., We're, going to, set, the, text
to be small and we're setting the color
to be gray 500.
Perfect. It should look a little bit
like this. Now, we're going to go three
divs down right before the main and
we're going to create the section for
both the search functionality and also
the table. We're we could start with the
search, but it doesn't really make sense
cuz why would you implement the search
without having data to search for? So
I'm going to actually jump the search
which goes at the top and we're going to
create the products table. Now, for the
products, table, to, do, this,, I'm, going to
create a div here. I'm setting the
background of this to be white. I'm
going to set the table section to be
rounded large. Giving it a border and
the border is going to be of color gray
200. And I'm also going to set an
overflow to be hidden. Now, inside of
this div, we're going to create a table
tag. Inside of this table tag, we're
going to, use, a, class, name, which, is, a
width that is full. Now, we need to set
the header of this table. So, we're
going to use the t head um tag and we're
not using any table libraries because to
be honest, you don't need to. You can
just easily make a table with normal
HTML and tailwind. Now, for the tad
we're going to set the class name to be
equal to bg gray 50. Then, inside of
here, we're going to set first a tr and
we're going to set a th.
Now, why is that? is because we're
setting a table row and the th is going
to be the table header. We are going to
have six different columns. We're going
to have the first column which is going
to be the name column. The second one
it's going to be the skew column.
The third one is going to be the price.
The fourth one is going to be the
quantity.
And we're going to have the low stock ad
property as well which could be empty as
you remember. And finally, we're going
to have the actions. Now, actions, it's
up to you. I will add a delete button
so you can delete a product really
easily, but you could also add an edit
product functionality or whatever you
want. Uh, but here is going to be all
the actions that you can apply to each
product. Now, you see over here, this
creates the header of a table. Now
let's go back here, and I want to apply
some styling to each of these headers.
So, it's actually going to be the same
style for all of the headers. So, we're
just going to copy and paste each of
them. For the main style, we're going to
set a petting X of six, a petting Y of
three. We're going to set the text to be
at the left, so it's not centered, and
we're going to set the text to be
actually extra small. The font is going
to be medium, and the color is going to
be gray 500. Finally, I want to make all
of the texts uppercase.
And this should be enough. Now we should
just copy this and paste it on every
single table header that we have. And in
the end, it should look a bit like this
which looks similar to what we have in
here. Now, let's go back here and let's
continue building the table with the th
head is done. So, we can actually build
the body of the table. So, I'm going to
say T body. And for the body, we are
going to apply some styles. So, we're
going to, set, the, BG, to, be, wide, as, well.
We're going to divide the table in the Y
direction. And we're going to add a
divide
of gray 200. Then, inside of this body
all we have to do is we now have to loop
through a list and create a structure of
uh rows uh that are going to of cells
that are going to be equal to what we
have here in the amount of columns. So
how do we do that? Well, we're going to
loop through the list of items which
represents all of the products and we
don't have that yet. So, we're going to
come up here and we're going to make a
simple request for all the products. We
actually already have the code for that.
If we go to the dashboard, if you
remember, we did make a query here that
gets all of the products, right? It's
this one over here. It's a very simple
query. It just fetches all of the
products. Uh we're going to call this
total
which uh total products whatever you
want to call we're going to set it equal
to uh prisma.product. I'm going to await
this and we need to import prisma from
our lib file. We also need to get the
user ID. Now to do that we're going to
call the user and await the get current
user and get the user ID from the user
ID. Perfect. Now we can actually use the
total products by going down here and
inside of the body, we're going to loop
through the total products. We're going
to map through it. And for each of the
products, we're going to render a TR
that is going to have the key and the
key is going to be the index. So we're
going to actually create a key value in
this, argument., And, we're, going to, pass
the key over here. And the class name
we're just going to apply a hover to it
just so that it changes a bit of the
color in case uh you hover a specific
cell. Now, uh I just realized it says
total products is a number. Did we? Oh
okay. Of course, we don't want to get
the count here. We actually want to get
the find many. We just want to find all
of the products that are equal to that
were created by the current user. So
this wouldn't make sense if this was
actually a count because this would be a
number. Now, what I want to do is inside
of here, we're going to create our first
um cell. The cell is going to be for the
product.name.
And we're just going to directly apply
some styling because again, all the
styles are going to be the same for each
cell. The style for this is going to be
exactly the same style that we have
here. We're just going to change some
minor things. So, the padding on the Y
direction is actually going to be four.
And we're not going to text left. The
text size will be small, not extra
small. And it won't be uppercase, nor it
will be font medium. Now, what I want
you guys to do is I want you guys to
copy this and paste it for each of the
columns that we have. I'm not going to
show myself doing it because it's going
to get repetitive, but I'll be back in a
second. Perfect. As you can see over
here, I added a value for the name, this
Q, the product price, the quantity, and
the low stock at the ones which were
optional values like this Q and the low
stock at, I checked to see if they were
uh not null. If they were not, if they
were null, we defaulted them to an empty
uh hyphen. So, you'll see that for the
values over here, we can see all the
values in the list of products. And for
the skew, since we never set any skew, I
think for any of them, it's always an
empty uh hyphen. Now, also, we converted
the price and we fixed it to two decimal
places. That's something that you can
decide for whatever you want. I prefer
to only use two decimal places. Now
there's one column that we didn't do
anything, which is the actions. And that
column is going to allow us to delete a
product. So I'm going to come down here
and I'm going to actually add the same
column here. But this column is a bit
different. So in this column we're going
to have a form which is going to have an
input in it. And this input is going to
be hidden. Now why is it hidden? It's so
that we can have a form in which we can
call and serve a server action. Now I'm
just going to call it ID and it's going
to have a value of the product ID. Uh
so we'll say product ID and then inside
of this input, we're going to have a
button. This button is going to say
delete. Let's add a bit of style to it
to emphasize that it's a bad thing. I'm
going to set the text to be red 600. And
when you hover it, it's just going to be
the same color, but a bit darker.
So, this is what we have. You can hover
it and then you can delete the specific
product. Now to make a delete we want to
get this form and we actually do want to
use this input. As you can see we are
serving the product ID as part of the
value of this input. Why? Because we're
going to have a server action that we're
going to pass this product ID as part of
the, form, data., So, in, here, we're, going to
pass an action. It's going to be an
async function that will give us access
to the following. It's going to give us
access to the form data. And the form
data is going to include the value of
every input in this form. Since we only
have one input which has the value of
the product ID, that's a quick and easy
way for for us to access the ID of the
product from this form data. And we need
the ID of the product to know which
product to delete. Now, in here, we're
going to call a server action. We're
going to create called delete product.
And we're going to pass the form data.
Now, what is this delete product server
action? Well, it's something that we can
create in the lib folder. We're going to
create a folder called actions. And this
is, where, we're, going to, put, all, of, our
server actions. The first one is going
to be for the products. Everything
related to products that we need it to
be, as, a, server, action,, we're, going to
put it over here. So, we'll start by
creating the async function for the
delete product.
Now, like we assumed over here, it is
going to require us to pass a form data
of type form data. So, I'm going to copy
and paste that over there. Then, I
highly recommend that the first thing
you do with an operation like this is
make sure that the user is
authenticated. Even though we already
checked it on the route, you want to
double check because with stuff like
deleting, it's important that you
actually are secure of the operation.
So, I'm going to say const and I'm also
going to get the ID of the user. I could
get the ID of the user from here, but we
actually want to get the ID of the
product. So, I'm going to get the ID of
the product by saying form data.get.
And we're going to pass the name that we
passed over here, which is ID.
And then if this is null, we'll default
this to an empty string. And we want to
convert all of this into a string.
Now after this all we need to do is we
need to await Prisma dot
product.delete
menu. Now why am I using the delete
menu? Because I want to propose you guys
a challenge that I'm not going to
include in this video. Uh in this video
I'm only showing you how to delete one
item. But I recommend that you add as
well a selection over here where you can
select multiple items to bulk delete.
I'm already giving you the the way to do
it. you use the delete menu function.
And I want you guys to add that as an
extra to this video if you want to have
a bit more of a challenge. In our case
deleting many and deleting only one does
the exact same thing. We're going to put
here the where of what we're trying to
delete. And the wear is we're trying to
delete the product in which the ID of
the product is equal to the ID that we
get from the form data and also the user
ID of that product. So who created that
product is the user who is logged in. So
we ensure that the user has ownership by
checking also the user ID. Then when
we're done with that we can assure that
this is going to delete the product. How
do, we, test, this?, So, I'm, going to, refresh
this over here. And as you can see it's
givingven us an error but it's that
error is because we cannot pass a
function uh because this is not a client
component. And that's an issue, right?
We're passing here a function uh from a
form. It recognizes that we're trying to
delete like call have a browser
operation like an on click to a button.
So all we have to do to fix that is
actually come to this file and at the
top make sure that we turn this into a
server file. You'll see that now if I
refresh this, it is still going to give
us an issue. The reason for that is
because not only we have to use server
there but also use server in here as
well uh to make sure that to tell uh
Nex.js that this is a server
functionality. Now let's try deleting
the first product because that's the
most obvious one that we're deleting. So
I'm going to click on delete. And wow
you see that product doesn't exist
anymore. Let me refresh this. Yeah, it
doesn't exist. Now, one thing you guys
might have noticed is that all the
products are in different order, which
is not what we have over here. That's
because remember I played around with
the dates. But the important thing to
know is that product one doesn't exist
anymore, meaning that we correctly
deleted the product. Now, we have our
table over here. What I want to
integrate to to this is the search
filtering functionality. So, we're going
to put a search bar up here. And there's
different ways in which you can make a
search bar. I'm actually going to keep
this uh server focused. You can actually
make a filtering u uh table uh with a
search bar that instantly if you were to
use a client component but in this
example we're actually going to be
making everything as a server component.
So what I'm going to do is I'm going to
come over here going to go down above
the products table and I want to create
a div. Uh actually we should go below
the this div that we already have. Uh
still maintain above the products table.
We're going to add the section for the
search.
Now, inside of here, we're going to add
a div. And on this div, we're going to
add a form. Now, the form is for uh the
input. So, there's only going to be one
input, but on the div, we're going to
set a background to be white. It's going
to be long rounded large. We're setting
a border. And that border, we're going
to set it to gray 200. Now, we're
setting a padding of six. And inside of
this form, we should now set a class
name. It's going to be flex a gap of
two. And we're going to set an action
here. The action is going to be
slashinventory.
And we're going to set a method which is
going to be a get because this is going
to be a get request when we submit this
um action. Now you might be asking
yourself why are we making this a an
action that isn't the slash inventory
because usually when you pass an action
you pass a callback function right well
in, reality, what, we're, going to, do, here
is at the top of this component uh we're
going to filter through the uh data
directly with the uh whatever we have on
this input. we're actually going to be
using the value of the input as part of
the uh search params of this route and
thus allowing us to whenever we call a
get request with an action equal to the
route of this page, it is going to
refresh the page to be able to execute
that. So what we need to do in here is
inside of this form, I'm going to add a
input
and we're going to set the name of this
input to whatever the value is. Now the
thing is I'm going to call this Q and Q
will stand for query. It's just the
query that you're trying to make for the
product. Now we're going to put a
placeholder here. It's going to be
called search products.
And in here we're going to set a class
name which is going to be flex one. Then
padding x of four, padding y of two. And
we're setting a border with a border
gray 300. It's going to be rounded
large. And we're also going to focus set
the border to be transparent when we
focus on it and save this. Perfect. Now
below this input, we need to have a
button to confirm it. So, we're setting
a button here, writing the label to be
search, and then in the button, we're
going to, set, a, class, name, padding, x, of
six, padding y of two, a bg of purple
600. The text is going to be white
and we're going to set it to round it
large. And when we hover it, the color
will change from BG purple
to 700. Perfect. Now we have this. If I
were to search for a product here
nothing happens other than the fact that
now we refresh this route. And the route
now has a parameter, a search param
which includes a Q, which is the value
and whatever we put in that input. So if
I were to search for uh just a and click
search, that will be replaced with that.
Now, why do we need that? Because since
this is a server component, we can't use
states, right? So, that's hard for us
because we can't use a way to get that
data and keep it into a state and then
use it. So, we do it through this. We
set the search param at the top over
here. And then what we do is
we now get that search param in the
props. So, to get the search param
we're going to get the search params.
And we'll set the type of it to be
search pars which you can get the type
of it is going to be promise and inside
of this promise is going to return an
object. That object is going to include
a q and in that q is going to be of type
string. Now before we even fetch the
data over here we're going to uh get the
search params. So I'm going to say con
params is equal to await search params.
we're going to get the value for Q. So
we need to make sure that there is a
value for Q. So I'm going to say if
params do Q is true, then we get it. If
not, we set it to an empty string. And
the result of that we're going to trim.
And we can trim by using thetrim
function.
Then what I want to do is I want to
basically go to this wear function over
here. And you see how we are quering for
a product where the user ID is equal to
the user ID. Now we also want to utilize
this uh property which is you can add
over here the field for example name
which is the name of the product and you
can only query for products in which the
name contains whatever Q is. Now
obviously,
this will mean that if I do this, you'll
see that it kind of it will work. It
it's already working because, as you can
see, it's uh not showing anything
anymore. But if I were refresh uh wait
let me actually just remove this. You'll
see now it shows everything. If I were
to write product 4, it should only show
product 4. It doesn't. Why? Because we
actually didn't write uh product four
exactly. You see how the P is not
capitalized. But if you were to uh look
over here, the P is capitalized. So to
make sure that it accounts for that kind
of scenario, we need to set the mode to
insensitive.
And when I do that and I were to search
for product 4, it now actually accounts
for product four. It doesn't care if
it's capitalized or not. Perfect. Now we
are sure that it works if we have a Q.
But what happens if there's no Q?
Still works. Perfect. Now we're pretty
much done with that uh searching. We can
search here for product
six or five whatever and it will show up
just that product. Now what I want to do
is we don't want to see this entire
table at once. We actually want to
utilize pageionation for this. But to
utilize pageionation, we actually need
to get the total amount of pages that
this will be. So what do I mean the
total amount of pages? Well, we want to
determine how many items are in each
page. You see here we have 1 2 3 4 5 6 7
8 9 10. So 10 items per page. I think we
have here like around 20 something like
28 items. So there's three pages. In the
last page there's less items. Uh if I
were to go here as you can see. So it'll
be kind of the same thing with us over
here. So we need to determine how many
pages are there. And to do that we get
the size of the page that we want. So
the size of how many items we want per
page. and we divide that number from the
total amount of products. So the way
we're, going to, do, this, is, we, have, the
total products over here and but that's
not a number. Obviously we could just
say total products.length. But the
problem with that is that it won't
actually account for our pageionation
because we don't want to fetch all
products at once. We actually want to do
the opposite with this over here. We're
not fetching all the products and
displaying them at once. We fetch them.
We only fetch 10 first and then we fetch
more when we go here. that saves us
having to fetch a bunch of data. So what
we want to do to do that is we actually
want to make two queries and combine
them. So I'm actually going to utilize
that logic that we did before where
we're going to say
await. So we're going to set this to
await promise
doall.
We're going to pass an array in here.
And in this array, we're going to first
pass the first query. And the first
query is actually going to be a
prisma.product.count.
We're going to count uh the amount of
products based on this search. So you
see how we have this wear search over
here which is a it's this property where
we're searching for the name. We're
going to reuse this twice. So I actually
want to extract that. So I'm going to
create a object called wear. It's the
same thing as we have over here. And in
this wear, we're going to have the we're
actually going to copy this entire thing
and we're going to paste it in here. So
it's both the user ID and the name. And
now, we can just replace this with the
wear. Uh or in this case, just do this.
And uh in this case, uh we're also going
to pass the wear inside of here. Now
we're getting an error, and that's
because uh there's a possibility of it
of this part over here being null. So
what we want to do actually is we want
to do this. We want to put three dots
and create a check to see if Q is null
or not because if Q
is uh not null then we do want to put
this object over here. But if Q is null
then we only want to put an empty object
and that's going to uh continue having
an issue. Oh, okay. I'm just going to
actually change this to say as const and
the error should go away. It's just a
simple TypeScript error. Perfect. Now we
have this wear object and we have it
twice. Now we can get this and put it as
a comma over here as well. So we have
two queries. We're going to get from the
first one the total
uh amount. So the total uh count and the
second one is items. I know we are using
the total products but now want to
replace that with uh with total with
items. Perfect. And the total count
should return the count of the the the
total items. And then inside of here
we're going to calculate the total pages
by saying total pages is equal to math
domax. Why are we doing math domax?
Because if there's zero products, then
this value is going to return zero. And
I don't want to have zero pages. I want
to, have, always, at least, one, page., So, we
do a math max of either one or the total
divided by the page size. Now we don't
have a page size variable. We're going
to create one over here. const page
size. And how are we going to calculate
that page size? Well, I'm just going to
set it to 10. That's what I want. The
total is going to be the total count.
Now, this value can be a decimal, and we
don't want a decimal value for the total
pages. So, I'm actually going to set a
ceiling to this. And the ceiling is
basically it's going to round to the top
the highest number. It's going to round
up. Perfect. Now, we have the amount of
total pages. And what we can do is we
can go here below our table. So, we go
below the table. We'll go one div down
and we can check to see if the total
pages is greater than one because if it
is, then we want to render the
pageionation control because there's
multiple pages you can go to. So, we'll
start by just adding a class here. I'm
going to say BG white. I'm going to
round it large. Set a border and a
border
gray 200. Also, a padding of six.
Perfect. Now, you can see that we
already see this down here because for
sure total pages is greater than one.
Now, inside of here, we actually want to
create a component. It's going to be
called pageionation. Now, why do we need
to create an extra component? Well, it's
because this is going to be a lot of
logic and I think it could behave in
itself and we can actually reuse it if
we were to add it to another part of the
project. So, we're going to come here to
the, components, folder, and, we're, going to
create here the pageionation.tcsx.
Now, inside of here, we're going to
export default function. And we're going
to call it pagionation.
And it's actually going to have a good
amount of props inside of it. So we're
going to define the type of the props.
We're going to say interface
pageionation props. And what do we need?
Well, to do pageionation, we need the
current page, which is a number. We need
the total pages, which is a number. We
need the base URL because we're doing
our pageionation through the search
params. And we need the actual search
params that we get from the route. So
it's going to be a record, which is a
string. It's like a map of a string with
a string. That's what a search par is.
Then in here, we're just going to
destructure all of that. We're going to
set it to pageionation props. And we can
just come here and get all of that. We
can get the current page, total pages
base URL, and search params. Perfect.
Now, inside of here, we're going to
first check to see if total pages is
greater is less than one. So if it's
less than or equal to one, return null.
Now why are we doing this? Didn't we
already check for this over here? Yes
technically, but we should still make
sure inside of the component as well in
case we ever make a mistake and don't
check and pass that on another component
in our project. Then what I want to do
is I'm going to return a nav which is
going to have a class name which is
going to, be, display, flex., It's, going, to
be item center. We're going to justify
this to the center and a gap of one.
Then inside of this nav, we're going to
have the structure. First, it's going to
be a button which is going to be
represented by a link. And this button
is going to have an icon. This icon is
going to be chevron left because it's a
left icon. And we're going to put a
label saying previous. Now, it's going
to complain because we need to put an
href. So right now I'm just going to put
an empty href. Uh just something like
this. Uh did it not import this also?
Yeah, import from next link. Perfect.
Then I'm adding a forward uh button. So
it's going to say uh next
over here. And it's not going to be a
chevron left, it's going to be a chevron
right. This is just the icon. You'll see
now uh if we were to import the
pageionation
actually there's a lot of props we need
to pass. So let's do that before we
check it out. So I'm going to pass the
current page which we can get by going
up here and calculating that. So I'll
say the page is equal to the number
of and we're going to keep track of the
page based on the search params. So we
actually are going to add over here
another thing to our search params
called page. And again if you're still
confused with pagionation the page is
just this which page are we on in our
pageionation are in page one page two
page three you can choose right now the
page is going to be kept in the search
bar. So we're going to create a string
in, the, search, par, is, going to, be, page
and down here we're going to get that
page and transform it into a number. So
we're going to say params.page
and if it's no we'll defi default it to
one. And if this value is completely
empty or it's something crazy like it's
negative -2 that doesn't make sense
right. So if it's anything less than one
then we're going to actually set it to
one. And we do that by saying math domax
and putting one as the other option
because then if this turns out to be
negative number it actually defaults to
one. Now we pass the page as the current
page. The second thing is the total
pages. So we'll pass the total pages and
we have that variable over here. Then
the base URL is just because we can
reuse that in the rest of the project. I
don't actually reuse it in this tutorial
but you could reuse it if you want to
create more pages.
Then I want to pass the search params.
And the search params looks like this.
It has the Q and it has the page size.
That's a variable we're going to create.
And the page size is going to be equal
to a string of the size of the page
which in this case is 10. We want to
keep track of that as well in the
pageionation. Now we can actually see
what we're doing. If I go over here and
go down, we see these two ugly links.
That's okay. We can make them look
better. So I'll start with this. I'm
actually gonna come over here. I'm going
to add a class name. And in this class
name, I'm actually directly going to use
back because we're going to do some
conditional uh styling here. And here
I'm going to say display flex item
center padding x of three, padding y of
two,
text small, font medium. I'm going to
round it large. And then I'm going to
insert some conditional styling
depending on if the current page is less
than or equal to one. We want to do
something. So if it is less than or
equal to one, then I want to set the
text to be gray
400. And also cursor not allowed. Now
what is cursor not allowed going to do?
Well, let me show you. I'm also going to
set a bg gray to be 100. And this should
be good to go. Then we want to put just
another style. So what this is going to
do is if we are in the first page, it's
going to show it grayed out and also
have this little icon on your cursor
showing that you can't click it. Even
though right now we can actually click
it. We actually have to disable it.
Perfect. Now the other styling is if
it's not like that then we want to make
it be gray 700 and allow it to be
hoverable. Perfect. Now if we go back
here uh I also want to actually disable
the input in this case. So I'm going to
say area disabled or just disabled
whatever you want. And I want to set it
to be only disabled if the current page
is less than or equal to one. That
should make it such that we can't
actually click it. Perfect. Now what we
got to do is copy this entire logic and
put it over here on this link as well
but change it. Instead of detecting if
the current page is less than or equal
to one, we check to see if the current
page is greater than or equal to the
total amount of pages. Same thing with
this over here.
Perfect. And then we should get uh we
can't actually pretty much see anything.
Oh, did I add the why did I write
previous over here? Okay. Yeah, we can't
really see it because we're not in the
in the last page in this case, but
great. Now, what we want to do is we
want to calculate the amount of pages
that there are. So, you see we have
three over here. We want to show a
button for each of them. And we only
want to show the ones that are visible.
So, to do that, we're going to create
here a function called get visible
pages. And what this is going to do is
it's going to do two things. It's going
to give us the actual visible pages, the
amount, but also if there are a lot of
products in here, right? There are like
500 products, we're not going to show, I
don't know, 30 pages appearing. We'll
put three dots at some point to
represent that there is a range of more
pages. So to do that, we're actually
going to come over here and we want to
do the following. We're going to start
with defining a variable called delta.
So delta will be uh how many pages we're
going to show before and after the
current page. And I think a delta of two
makes sense. In our case, it's only
going to, be, three, pages., I'm, going, to
try to add more data in the end so I can
see it fully working. But uh delta would
just mean that means that if you're in
page five, you will be able to see
appearing down your screen pages three
four, five, six, and seven because
you'll see two above five and two below
five. Perfect.
Then we're going to define a array
called range. This will store the raw
numbers around the current page. We're
also going to create a range with dots.
And it will not only include numbers
like 1 2 3, but it will also include
dots like this to represent that there
are more pages there. And we don't want
to display all the pages. Now the next
thing I want to do is I want to build
the middle page range. To do that, I'm
going to for loop over here. I'm going
to create a variable called I. Set it
equal to max to math domax. And I'm
going to say two and get the current
page and subtract delta
because that's the minimum amount of
pages we the minimum of delta we can
have. And we want to get the difference
in the in the current page and the
delta. Then we're going to check for
this until I is less than the total
pages
minus one
or whatever is less that or the current
page plus the delta. And we get that by
making it be a math.min
wrapping this around.
So we're going to say math domin.
Perfect. Then in the end we'll just
we'll just increment by one every single
time and we'll close this for loop. Did
I accidentally
yeah one extra parenthesis. And now what
do we do in this for loop? Again we're
trying to build the middle range. So it
is going to start with the current page
minus delta but that's never less than
two since page one is handled separately
through our links. And it will end with
the total with the current page plus
delta. But that's also never going to be
greater than the total pages minus one
since the last page again is handled
separately. So what we're going to do
here is we're actually going to use this
range array to push every one of these
numbers inside of this array. So a good
example of what this will look like is
something like this. If the current page
in this uh uh function is six, the total
pages is 10 and the delta is two. This
will return this 4 5 6 7 8 and those
will be the pages displayed at the
bottom over here. Now what we want to do
is we want to always include page one.
How do we do that? We check to see if
the current page minus delta is greater
than two. Then we're going to use now
the rage with dots and we're going to
push one and then include the three
dots. Why? because we don't want to put
the three dots uh as the first thing. We
always want to have the first page. If
not, if it isn't, then we don't need to
put the three dots, but we at least want
to use to always insert the first one.
So, we're going to say range with dots
push one. Then, regardless, we want to
insert the range inside of the range
with dots. So, we're going to push
everything inside of the range array.
Then finally we want to include the last
page. This was for the first page. This
was the logic that we built for the
middle page. And now we're going to
write the same logic but for the the
last page. So to do that instead of
calculating current page minus delta is
greater than two. That's not what we
need. We need to calculate if the
current
page plus the delta is less than the
total pages minus one. Why minus one?
Because arrays obviously start from
zero. And then what we do is we do the
opposite. We don't set one first and
then put the three dots. We show the
three dots first and then we set the
length of the amount of pages or the
total pages. And in here we add the
total pages if that's the case. And then
in the end we just return the final
result through the range with dots. Now
don't get me wrong, I understand that
this might be a bit confusing. If you've
never done pageionation before, this is
definitely confusing. I recommend just
playing around with it and uh going line
by line and you'll eventually get it. As
you play more with it, you'll be able to
understand what each part of it means
and you will eventually get it. The
important thing is that this will give
us back the visible pages. So I'm just
going to call get visible pages and we
should get that value back. And when we
do, we now can go below the previous but
above the next. And we're going to loop
through the visible visible pages. We're
going to get each page and the key. And
then inside of here, we're going to get
the two variables. First, we're just
going to get the page, but we're going
to call it page number because we want
to convert it into a number since it
could be uh a string, right, with the
three dots. So, we want to convert into
a number to guarantee. Then we want to
get a boolean to let us know if we're
currently in that page as we're
rendering so that it has a different
style. We do that by checking if the
page number is equal to the current
page.
Perfect. And then finally, we're going
to return the actual UI for each page.
It's going to be a link which is just
going to have the page number. I suspect
that right now it's going to break
because uh wait, let me just put an href
here. The href right now is just going
to be an empty uh route. But I think
it's going to break because of the three
dots. Let's see. Uh actually, no, we're
not showing three dots, right? So, if we
were to actually let me try this. If I
were to forcefully pass this to be uh I
don't know 19 pages. Let's see how it
would look like. Yeah, this is how it
would look like. See, we have the three
dots over here. And as we move forward
through this, oh, I just made just made
the link take us to the homepage. Yeah
we still have to work on that for me to
show you guys the real value. But it
should actually push the three dots
forward as well. Perfect. Now, we got
this page number, but how do we style
it? Well, in the class name over here
we're going to again apply some
conditional styling. So, I'm going to be
utilizing back tick. Uh, and I'm going
to set the padding X to be three, the
padding Y to be two, the text to be
small, the font to be medium, and then
I'm going to round it large, and I'm
going to check to see if this is the
current page. Why? Because if it is
then I'm setting the BG to be purple
600,
and the text to be white. If it's not
then I want to set the text to be gray
700. And I want to hover it to set it to
BG gray 100. And then I want to set over
here the BG to be white. I'm setting a
border. And that border is going to be
gray 300. Now it will look a little bit
better. It looks exactly how we have
over here, right? But what happens if I
come here and I change this back to say
19? This doesn't really look that good.
I want it to actually look unique. It
looks exactly how it looks over here. So
instead of that, I want to first come up
here and I want to make sure that if the
page is equal to three dots, which is
what we made it be in that visible
functions uh the visible pages function
we have above. Then I want to return a
different UI.
So I want to return a span, not a link.
And this span is going to have three
dots. But then I'm going to come here.
I'm going to set the class name to be
equal to padding x of three, padding y
of two, and a text to be small. And that
text to be gray 500. Also, I'll set the
key over here. And I'll set the key over
here.
Now you should see that it actually
looks a lot better. But we really can't
move anywhere, right? As I click on this
buttons, it doesn't actually do
anything. And we technically still only
see uh like we see all the items
appearing over here. So, we'll get to
there. The first thing we want to do is
actually uh allow ourselves to move
through different items. And the way
we're going to do that is we're going to
create a function up here. This function
is going to be called get page URL. It's
going to, be, a, function, that, when, you
called it will actually uh take you to
another page and also return the value
of the new page URL. So what we need to
know is what is the current page that
will be a number and we need to know
where we want to go. So I'm going to
change the value in our params. So I'm
going to say new URL search params and
I'm going to get the current value of
the search params and then I'm just
going to change the value for page to be
equal to whatever we're trying to go and
that's going to force us to go to that
page. When I return
the
link to the inventory page which we can
get from the base URL which remember is
just /inventory
and then we put a question mark cuz this
is a search param and we insert the
params.2 string. What this will do is
when we call this for example let's go
to the most obvious one the going right
right because we're in the first page
already. So, if I click here and I go to
the href here and I call the get page
URL, where do I want to go? If I click
the right button, right? If I click this
button over here. Well, think about it.
We're trying to go to the next page. So
we're trying to go to the current page
plus one. How do we know which page
we're in? Well, remember it's appearing
here at the top. If I click next, it's
going to take us to page two. And now
we're here. If I click next, it's going
to take us to page three. And now we're
there.
exactly how we want. It keeps us taking
to the next page and you see that this
keeps expanding, right? Which is exactly
what I wanted. Now there is a gap in the
middle and there because of a delta of
two, it only shows two out of where you
are. Now it kind of makes more sense to
you guys if you guys didn't understand
it before. I hope it does. So what this
is what the get page does. You set you
you set it to an href and that makes it
such that you're returning that value.
You're returning a new URL with the
correct params. So, we're going to be
using that on every single link. We're
going to come up here and use this as
well here. But in this case, we're going
to say current page minus one. And then
on this one, it's a bit different. We
don't want to set it to uh any specific
calculation. We just want to set it to
whatever the page number we're trying to
go is. So, let's test this out. Can I go
to three? Yes, I can. Can I go to one?
Yes, I can. I can't go behind that.
Perfect. Can I go to 19? Yes. And I can
go forward. Great. Now, you might be
asking, why is it bringing us up all the
time? Well, this page is huge, and we
kept refreshing the page. So, that's
that's the thing. We what we want to do
now is filter the information over here
based on the page we're in. So, how do
we do that? Well, we have the
pageionation done. We have the
information about that in our URL. And
all it takes now is query for our
products based on that information. So
to, make, that, query,, I'm, going to, come
here to where we find all the products.
And we're going to first order them by
the date in which they were created.
That's something that I don't think
we're doing. And then I want to skip the
products in which the page minus one
times the page size, which is 10. Now
the page and the page size are below
this. So I actually want to bring this
up here somewhere. Maybe here. And the
page size as well. I'll just bring it
here so we have more space. And what
this is doing is it's calculating how
many items we're going to skip in
querying this based on the current page.
For example, if we are in page three, we
actually don't want to query the first
20 items
from the list of products ordered by the
created at. Why? Because we're in page
three and the first 20 items were in
page one and two. So that's what we're
doing. We're getting the current page
that we're in. We're subtracting one and
we're multiplying it times the page
size. If we are in page one, this
shouldn't be an issue. Also, we want to
limit the amount of products that we're
quering per time. We do that by using
the take property. Take allows you to
give a number. If I were to put two
you'll see that now it will only give us
two items. But if I were to put the page
size, it's going to give us an actual 10
items, which is what we set. And if I
keep going, it will keep moving forward.
Actually, let's make the page size be
something like five. I think that that
will make it look a little bit better.
You see there's more pages, but we can
keep moving them forward. And the
pageionation works perfectly. Great. So
this is pretty much it for the
inventory. Now, we've been using a lot
of fake data so far. And that's fine. We
added the the the data through the seed.
I think it's time for us to be able to
add our own data. So to build that
we're, going to, come, over, here, and, we're
going to open up the add product and
we're going to create a page.tsx.
Now inside of here, we want to export
default
async function
called add product page.
Then inside of here, we're going to
return. I'm going to return a div. And
we're, going to, first, get, the, user., So,
we're going to await
get current user just like we normally
do. And I need to make this into a const
because we're going to be using that
throughout our page. Then I want to do
the same thing I've done with the other
pages. I'm going to set a class name
with the minimum height of the screen
and a bg gray of 50. Then we insert the
sidebar. So I'll insert the sidebar over
here. And I'm going to set the current
path
to be equal to slash add product. We
should now be able to see this. If I go
to add product, we should see this over
here. And uh you see when we go to add
product, it actually shows the correct
uh path. Now below this, we want to
start by adding the main tag. And in the
main tag, we're setting a class name of
ML 64 and a padding of 8. Then in here
we're going to set the header. The
header will have uh actually I'll just
copy the header from the inventory page
because it'll be pretty much the same
thing. So I can just copy this and I'll
paste it over here. We saved some time
and I can just change the header. I'll
say add product. And in here, I'm going
to say add a new product to your
inventory. This page is actually going
to be pretty simple. Then we're going to
come down three divs and I'm going to
add the next section. This section we're
setting a class name of max width to
Excel. Then in here we're setting a div.
This div is going to have a class name
BG white. Then rounded large. We're
setting a border and a border gray 200
with a padding of six. Inside of this
div, we're going to add the form to
create a new product. Now, we're spacing
all the items in this form with a space
gap in the y direction of six. Then, in
this form, we're going to add a div with
a label. In this label, we're going to
say product name and then put an
asterisk. Then in this label, we're
going to say the label is an a label and
we're setting the HTML for it to be to
the input with an ID of name. Uh we
haven't made it yet, but we're going to
make it. We're also going to set a class
name. We're going to set the display to
block, the text to small, the font to
medium,
and the text to gray 700.
Also a margin bottom of two. You'll see
that it looks a little bit like this.
It's just one label appearing on the
left. Then below this, we're going to
put an input.
And this input is going to be of type
text. The ID is going to be equal to
name. And we're also giving it a name
which is equal to name. We're making it
required. And we're going to add a class
name. are setting the width to be the
full length, a padding ax of four, a
padding Y of two, the border, and then a
border gray 300. Also, we're going to
round it. So, we're going to say rounded
large, and we're going to focus the
border to be transparent
like we did before. Also, we're adding a
placeholder here. So, we're going to say
placeholder. We're going to say enter
product name. And we should get this
over here. Now the rest of the form
items, if you go to this, you'll see it
actually have different formats. For
example, this one will have a little
grid which shows two of them. So I want
to come below this div and I want to
create a div that is going to be for the
grid. So I'm setting it to display grid.
Then I'm setting the columns amount to
one. But on a medium screen and above
I'm going to set it to two, which is
what we saw over there. So calls two and
I'm going to put a gap of six in between
them. Then inside of this
we're going to copy this entire logic
and add it twice because there's two
inputs inside of it. So we should see
something a bit like this.
Now obviously they should change. It's
not, going to, be, a, product, name., It's
going to be the price and this will be
an input of type number. The ID will be
price.
Same thing with the name. We're also
going to put a step. And a step is just
how much will it increment, right? So
we're going to put it 01 so that it
increments like that. Like when we
increase the price, it's going to go
like this. See? And then uh we want to
make the minimum amount be zero. So we
can put a negative price. It's required.
And the placeholder is going to be 0.0.
Now this is I made this the bottom one
but it doesn't really matter. The second
one is the quantity.
So we'll put quantity and uh it'll be
here in HTML for quantity. This will be
for price I forgot to change. And in the
text over here the input we're going to
set the same thing as we did over here.
We're going to set it to be um an input
of type number. The ID is going to be
quantity. The name will be quantity. And
for the quantity we do want to put a
minimum amount. So we're going to say
minimum is equal to zero.
and the placeholder is going to be zero
as well. Then it's time for us to write
this Q. And for this Q, I'm going to
copy the logic of the product name
because it's going to be a text as well.
We're going to go down two divs because
remember we had that grid div. And I'm
going to add uh actually should we go
down to Yeah, we should. We're going to
add the next group which is the label
for the skew. But since it's a skew
it's not required. So it's optional.
The HTML here will be skew. And then I
just have to change both of these. And
this I'll just say enter skew. Then the
next one is going to be a number. So I'm
going to, copy, this, one., We're, going, to
put down below this. And this one is
going to be for the low stock at. So low
stock at. And I'll copy this. Paste it
twice over here. And the we're not going
to put a step. And the minimum is going
to be zero. And yeah, we're going to put
a placeholder of enter low stock
threshold. Then finally, we're going to
add the button to submit. So I'm going
to come here. I'm going to add a div
class name of flex and a gap of four.
And we're going to have two buttons. The
first one is a button to um submit. So
I'm going to say add product.
And we're going to come here. We're
going to make this be of type submit.
Class name is going to be a padding X of
six, a padding Y of three, a BG purple
600. The text is going to be white.
It's going to be rounded large. And when
you hover it, we're going to make the
BGB purple 700.
Then we're going to add a link.
This link is going to be for
taking us back. So, taking us to the
inventory. So, I'm just going to make it
be a cancel button that will look like a
link. So, I'm going to add this
as a class name over here, but I'm going
to change the color. Instead of purple
it's, going to, be, gray., And, it's, going, to
be 200. And then this will be gray. Uh
I will say like 300.
And then the text will be gray
800. And I need to put an href here. So
I'm going to put an href to
the slashinventory page. And then it
should look a bit like this. Perfect.
Now, we can actually submit this. But
nothing really happens. If I were to put
a number here, uh, and I were to put
something submit. Absolutely nothing.
Oh, why is it called price? You see, we
got this data as the form data. I forgot
to change the this over here to say low
stock at and make it optional.
Perfect. Now what we need to do is we
need to pass a action that is going to
be part of this action over here. So
we're going to create a server action.
It's going to be in the same file as the
delete server action we have. And it's
actually going to be very similar. What
we're going to do is we're going to
create a create product
server action over here and we are still
we, are, going to, get, the, current, user, but
what we need to do is we need to first
validate
for whether or not the form data that we
got is valid. How are we going to do
this? Well, a great way to do this is by
using a library called zod. So zod is a
great validation library. We're going to
install by saying npm install zod. And
it's going to allow us to define uh the
shape of how we want our data to look
like. And if the user tries to create a
product that doesn't follow that
pattern, it is going to uh spit out a a
custom error message uh preventing them
from submitting. Now, how do we use ZOD
here? Well, I'm going to import Z from
ZOD.
And we need to create what is known as
the schema. We're going to call it
product schema. We're going to use Z the
object. And in here we're going to
define each field in our form. So we
have name, we have price, we have
quantity and we define the structure of
each of them. For example, the name is
going to be a string. So we say Z.tring.
And I want to make it such that it can't
be an empty string. It has to be a
minimum amount of characters of one. And
if that is not met, then I'm going to
put this custom error saying that the
name is required.
So this is what we do. We do this for
each field. And there's some cool
properties that we can apply. So I
already did this. This is how I decided
to to make it. So we made the price be a
number and it can't be negative. If it
is negative, we somehow it's negative.
We have to error this message out. Same
thing with quantity. We made it such
that it's an integer because price is a
decimal but but quantity is a full
number. And we also made it not be
negative. The skew and the low stark are
both optional. So we use the optional
field over here. Now what do we do with
this product schema? Well, the first
thing we do in our create product is we
make sure that what we get back
from the form data is parsed correctly.
So I'm going to parse our uh form data
using the product schema. We use the
safe parse function and we pass an
object with each of our fields. So we're
going to pass here the name field and we
can get whatever the user is passing by
whenever we pass here the create product
action. Uh the names of the fields are
going to be present and we can get it
through the form data.get get for
example name and we can do this for all
of the other uh fields as well. So it
will end up looking a bit like this. Uh
the skew and the low stock we're
defining them to be undefined if it
doesn't get anything so that it knows
but it's okay because they are optional
as well. Now the important thing is if
the parsed value is not a success
meaning there's an error here you want
to do something I'll just throw a
generic error here saying that the
validation failed
and then I'm going to try
and I'm going to catch the operation
to create a product. So, I'm going to
throw a new error if there's an issue
but I'm not actually going to include
the error because I don't want to give
indication of how our back end is set
up. I'm just going to say failed to
create product.
Now, in the try here, what I want to do
is I want to await Prisma.create.
And then in here, I'm going to pass the
data. Now for the data, what I want to
do is I want to pass an object and I'm
going to insert the parsed data. That's
how I get the data after it's been
parsed. Then I want to include the user
ID because I only want to create the
data with this the the current user
signed in. So I'm just going to use the
user ID to get that information. And
thus we are creating a product with a
user ID equal to the ID of the user that
is logged in. This should now allow us
to create a product. Let's try creating
something.
Imagine I'm trying to sell a sponge. I'm
going to add here a sponge. I'm going to
say that I have 900 of it and that the
price is uh $8. Not going to put a skew.
Not going to put a a low uh stock
threshold. I'm going to click add
product. Uh oh, I made this required.
That's actually a good thing that we
tested this cuz I forgot to remove the
required fields from this queue and from
the low stock at. But now let's click
add product. And if everything is
correct, it should have added. Now
nothing interactive happened in our uh
front end. So, we're going to have to
change that. But if I go over here and I
refresh this, we should now see the
sponge appearing over here. Now, to make
it such that it redirects us or
something, we have to add here a
redirect function from next navigation.
And I want it to take us to the
inventory. And now that we added the
redirect, it should actually um redirect
the user to the inventory page. Great.
We're pretty much done with our project.
Now, the last thing we need to do is add
the ability to come here to the settings
page and see something. In this case, we
want to just show this uh little
settings page over here. Also, one thing
is, if you notice, we have this loading
state that appears on all of them. I'm
going to show you guys right at the end
because it looks a lot better if you do
that. Now, for the settings page, it's
actually very simple. What I'm going to
do is I'm going to come here to the
settings and I'm going to click new file
page.tsx.
Then inside of here, I want to export
default async function
called settings page. Then in here I'm
going to get the user by saying user is
equal to await get current user. Then
I'm just going to actually copy what we
have here for the first part because
it's going to be pretty much the same
thing. I'm going to return and I'm going
to paste this. Then I do need to close
this. So I'm going to close the main tag
and I'm going to close the div. I need
to import the sidebar and not the
sidebar from Lucid React. actually the
sidebar from the components folder and I
need to change this to
slash settings.
Then I'll change this to say uh this is
the settings page. So settings
and here we should say manage your
account settings and preferences.
Perfect. Now you might be thinking this
is going to be huge, right? Because we
have all this stuff. You can do a bunch
of stuff inside of the settings page.
You can, you know, choose the email
settings. You can sign out. You can
change your name, your profile picture
anything you want. You can even enable
multifactor authentication. But
actually, this is the easiest page we've
worked on so far. All we're going to do
is create a div that is going to be the
center of the page. So, max width 6x.
Then,, inside, of, it,, we're, going to, have
another div with a class name that is bg
white. We're going to set the rounded to
be large. We're setting a border and a
border gray 200 with a padding of six.
And then inside of this div, we're going
to set the account settings. And the
account settings component is a
component from stack frame. So the neon
o library. And it is going to allow us
to show the settings. Now I want to make
it be the full page. So I'm actually
going to pass here full page. and it's
going to give us literally everything we
need about our profile. And we should
see this over here. Now, this isn't
technically the same thing as we see
over here. And there's a reason for it.
We need to make some minor changes. Now
you might be asking yourself, why does
it look completely different from what
we have over here? Well, it's actually
because this is the same thing, but I
accidentally cut this part out because
we didn't pass uh a margin
to the main tag over here. So, this main
tag should actually wrap this two so
that there's a proper margin. And you
see that now if I refresh, we do get the
whole settings page. So, you can see
everything and manage everything related
to the settings of the user. And it
works perfectly. Now, how do we add the
final thing which is a loading state so
that the the sidebar doesn't disappear
every single time? Well, to do that, I'm
actually going to add a loading state
that applies to every single route. And
that loading state will exist over here.
We already have this loading.tsx. This
was created by stack frame because what
it does is it already has some loading.
If you can see over here, while we're
navigating this items, it has its own
loading and that's part of what they
already do for us. But for us, we
actually want to add some skeletons so
that it makes it look like this. So what
we want to do is we want to have a
component that is the loading state. And
that component will always show the
sidebar. The only thing that changes is
it shows a little bit of some skeletons
in the middle of the page. So to do
that, I want to do this. I just pasted
here my entire loading component for
this project. I'm not going to go into
detail about it, but I did write some
comments. Um, basically all we're doing
is we are creating a bunch of skeletons.
We're always showing the sidebar and
whenever we navigate between the stuff
it now shows that little pulsating
skeletons every single time. And the
best part is that the sidebar doesn't
disappear. Also, I just realized there's
a small thing that does change uh the
title of the page cuz you see I did
change a bit the logo from the other app
I had. So, I do want to change that. If
I come here to the sidebar, so you see
main content show sidebar. If it does
show the sidebar, then we do want to
remove the the title. So, we created
this loading sidebar over here. And in
here, we actually want to create the or
get the title portion of the sidebar
right? This part over here. And just
paste it on the loading sidebar. I'm
pretty sure it's this. And then now it
should keep the same.
Perfect. And this is basically it. Uh we
created an entire inventory management
system. It has a beautiful dashboard
with a bunch of data, the ability to
pageionate and read data from a table
and also the ability to add new products
and manage your account settings. If you
enjoyed this video, please leave a like
down below and comment what you want to
see next. Click the link in the
description to check out Neon if you
haven't already. I use them for a lot of
my videos and a lot of my personal
projects. They are a great service and I
really appreciate them sponsoring this
video. Again, if it really helps the
channel. So, if you guys could check
them out, that would be great. Also
don't forget if you want to learn
Next.js, click the link in description.
You'll find the link to WebDev Ultra.
That's my course platform. And we just
launched our new course. So, if you want
to check it out, we have a discount code
that will be in the description as well
for the first 100 users. So, thank you
so much for watching this video and I
see you guys next time.
[Music]
Check out Neon: https://get.neon.com/pt1 Want to Learn NextJS? š Check out my Course: https://www.webdevultra.com/nextjs Use code Next100 for 20% OFF! š Video Resources: Code Repo: http://webdevultra.com/video-info/L5CsIkO5xv4 š» Check out my Blog: https://www.pedrotech.co š¤ Follow me on Twitter: (https://twitter.com/pedrotech_) šø Follow me on Instagram: (https://www.instagram.com/pedro.fmachado_/) š§³ Follow me on Linkedin: (https://www.linkedin.com/company/pedrotech) šØāš» GitHub: https://github.com/machadop1407 š Business Email: pedro@pedrotech.co Timestamps: 00:00:00 | Intro 00:01:40 | Setup Project 00:08:40 | Authentication 00:35:08 | Creating Sidebar 00:53:08 | Dashboard Page 01:49:08 | Inventory Page 02:13:08 | Pagination 02:38:08 | Add Product Page 02:50:08 | Settings Page