Now that we successfully spent a lot of time in the
administration area and on the product management.
Let's come back to the regular website.
Visitors, no matter if they are logged in or not,
they should be able to visit the shop and see the products
here as well.
Of course, they should not see the products
with the option of then editing or deleting them,
but they should see the products so that they are then able
to view the details of a product.
And ultimately also add a product to the cart if they want
to.
And for this all,
we can go back to our page, or back and code precisely,
and now work on more routes and more actions,
more controller actions.
Because we do, if we have a look at our routes,
have a product route that renders this all products page.
At the moment, we do it here in an anonymous function.
Now I want to add a separate controller,
a product controller,
which is for the regular customers in the end, where I do
render this route for slash products.
And where we then later also add a route for viewing
the details about a product.
So therefore in the controllers folder,
I'll add a new file, product or products dot controller dot
JS.
And in there I'll add a new function, get all products,
which should be a controller action that is responsible for
showing the all products page.
And therefore we can now go to the route for that.
Let me close to public folder, to the products route,
and actually grab this code here, and delete this anonymous
function here, and back in the product controller use
res render, customer products, all products.
And accept, request and response here.
And of course,
now we don't just want to render this page like this.
We now also want to fetch all the products that should be
displayed on this page.
And that can be done with help of our product model.
We're not limited to using that model for administration
purposes.
In that model, in the product model,
we do after all have a find all static method,
which does get us all the products,
and that's exactly what we need now for this all products
page that's facing our customers as well.
Hence, we can add an import to the product model
by requiring going up one level,
models, product dot model.
And then in this function,
we can add async in front of it, since we'll use async
await, because I want to call the product,
find all, which returns a promise and I want to
await this to get my products.
Now, as always, this could fail
and therefore I will accept the next
argument, so that we can try catch this.
So, try getting all products, and catch any potential errors
we might be facing and only render if we succeeded.
So inside of the try block, and then the catch block,
I'll call next error, two forward this potential error,
to the error handling middleware.
And then here in the try block where we know that we
succeeded, I will pass a second argument,
a second parameter value to this rendered template.
And that will be my products data here.
So the products which have fetched here are passed
as products into this template here, like this.
They are made available under a product key.
And that means that now in this all products template,
we can loop through all the products to output the product
items there as well.
Now, before we do that, let's first of all,
export this controller action.
And again,
I will export an object so that we can group multiple
controller actions together in that object and export all of
them.
So here I will export, get all products,
as I want to name it.
Hence, I added the S here, like this.
And then in the products route, we can import this,
the products controller.
We can import this here by going up one level, diving into
controllers and using the products controller.
And then here for this, get slash products route.
We can use products controller dot get all products
and point at this action.
Now, however, in the customer folder, that's important,
not in the admin folder but in, the customer folder.
There, I have all products EJS.
And here I now want to output my list
of products by using a for-of loop here in my template.
And by going through all the products, which I get,
and we have that products key here,
because we're passing that into the template in our render
function, in the controller action.
And there, I then want to repeat list items.
And in those lists items,
I in the end want to output product items just as I'm doing
it in the admin area.
There, I have these product items and in the end,
I want to use the same approach now,
the only difference will be that I do want to show
a different action.
But since I want to use the same snippet,
we can actually turn this product item
EJS into a shared include.
So we could go to shared, and in includes there,
we could copy in the product item.
So in the shared includes folder,
we could also place it in a sub-folder there,
but I'll just add it into includes like this for now.
And then back in the admin, all products EJS file,
I now do want to include that shared product item file.
So in the admin folder, I go up one level.
So that I'm in the admin folder,
I was in the product folder.
I go up one level into the admin folder,
go up one level so that I'm in the views folder,
and then dive into the shared folder,
and from there into the includes folder.
So that I'm now in the shared includes folder,
where I find the product item.
And with that we can remove the product item
here in the admin products includes folder.
And it's now in yet the same path.
Hence, I'll copy that from the admin all products EJS file,
which I want to use in the customer products,
all products EJS file.
We go up two levels, so that
from inside products in the customer folder,
we go into the views folder, and then we dive into shared
includes, and use that product item EJS file.
And I still pass my product data under a product key into
that snippet, because in that product item snippet,
I am referring to product.
Now, the actions of course will differ,
based on whether we're an administrator, or not.
And therefore actually I want to check if locals is admin,
if that is true here, and only if that is the case,
I want to show these two actions.
Because as a regular user we should not be able
to edit or delete items.
Instead in the else case,
which we can write like this here, in the else case here,
let's also close this of course.
In that case, I want to show a regular link,
which still gets a class of BTN and BTN Alt though.
Which leads to slash products slash the ID of that product,
which should give us the detail page for the product,
which we have yet to add.
Here in the URL we can use EJS to inject the product ID
into that generated URL, or into that generated path here.
And there I'll say, View Details.
So that's the link we see as a non-administrator.
Now, with that, if we reload here,
I don't see any products because I don't have any products
yet.
If I quickly log in as an administrator,
and I manage products, and I add a new product,
like a keyboard,
and I choose a file, this is a keyboard, give it a price.
It's awesome.
Definitely helps with typing like this.
Then we have it here, and let's add a second product here,
The Magic Track Pad,
which I'm using, great for replacing a mouse.
This helps a lot with smoothly navigating around
on your system.
I'm using it for recording my videos.
If I click save, I have this as well.
And now if I do log out and I go back to the regular shop
page, which our customers see,
I see my products here as well.
However, the styling is missing, and the styling is missing
because of course, in the admin all products page,
we are including the products CSS file.
We need to do the same thing in our customer facing all
products page now.
So, here, before we close the head tag,
we want to include this link, which links to styles,
products CSS.
Once we do that, if we reload, we're one step closer,
but we're still not there, because in our admin
all products EJS file,
we also see that we've got this ID on the unordered list
that holds our products.
And of course that's missing at the moment in the customer
products, all products EJS file.
There we don't even have the unordered list
and we definitely need that, of course.
And we need that ID on that list because that ID is used for
styling.
Now, we won't have a clash with that other,
same ID in the other page,
because these are two different pages and they are loaded
for different paths.
So this ID will at most be once on the page.
Now we can move this code here into this grid,
into this unordered list here, like this.
And now with that,
if we now saved this customer facing all products page,
now we've got the proper look here.
Now, regarding the details, we might want to center this.
And to achieve that we can go to the products CSS file,
which I now use for both the administration and the customer
part, which is fine.
And there for product item actions,
I, in the end, now just want to have justify content center.
If we do that, it's centered.
Let's quickly check if the administration styles are broken
now, if I log into my admin account.
Nope, that looks good.
So, therefore now this works.
And now we want to make sure that when we click
view details, we actually show the details page
for a product.