Let's dive into orders and let's make sure that we can
actually click this Buy Products button and order our cart
content.
For this I'll start in cart EJS
and there,
I want to start by only showing this button,
if you are logged in, because if you're not logged in,
as I am here at the moment,
you shouldn't be able to click this button because you can
only buy products if you are logged in.
So they have four here,
I'll add a little check where I check.
If locals is off that's that field,
we have to determine whether this user is authenticated or
not.
And only if that returns true I'll show that button.
Otherwise we won't show it. If we don't show the button.
So as a L's case. So if the user is not authenticated,
then I want to show a fallback paragraph instead
where we could say, log in
to proceed and purchase
the items.
Something like this
So now if we save this
we have this fallback text here.
We could change the styling of it, um,
especially on mobile views.
This doesn't look that great on mobile devices.
We'll do that in a second. If I do log in, though,
if I do log in with my user here,
then you will see that I can actually click Buy Products.
Now let's fix the text. If we are locked out and for this,
I want to select
this paragraph here in cart total
and to select this in a unique way,
I'll give it an idea of,
cart,
total,
fall back.
It's a unique ID and we can select this and card CSS now to
change the styling of this
and here
I'll selected by ID
and set the phone size to one REM for example,
the font weight to normal like this
and see that this has no
effect because if we inspect this,
we see specificity and action.
I do have my cart total fallback styles here,
but they are being overwritten by the more specific selector
here because selecting a paragraph ends out of an element
with that ID is more specific in CSS world
then selecting one element by just its ID
because this selector has more information to it.
It's more specific and therefore this rule wins.
So to ensure that this rule wins instead,
we've got various ways of improving
the specificity.
For example, by selecting the item with that ID,
that's inside another item with the cart total ID,
which is a layout we have here.
The div has cart total as an ID
and now we're providing a more specific rule of selecting
the item with this ID inside of it.
That would be one way of being more specific.
And now with that, this looks better, I would say,
so this is now step one.
We only showed a button when we want to show it. Step two.
Of course now is the more important step where we actually
make the button do something.
Now, if we log in with a valid user account here,
then we can click this button. We can,
of course also add more items to the cart.
This all works.
Here adjusts the, uh, tiny issue where I got 1, 1, 1 here
instead of 3, the reason for that is in the cart model
actually, where we increase the quantity by one,
we should make sure that we always force a conversion to
numbers. First, before we try adding a one so that
we ensure that we always are working with numbers and we
don't just concatenate one to a long string.
So let's save this, remove this
and actually
clear the entire session, now that I fixed this
by removing that cookie.
And then reloading
And now let's try this again,
add a cart item here,
like this,
that now looks better.
And now if I do log in here.
Like this.
Add this one more time, that looks good
And now let's make sure that this Buy Products
button does something meaningful.
Now for that,
we've got various ways of making it do something.
One thing I want to do here.
Is...
In art EJS.
I want to wrap this button into a forum because I want to do
a standard form submission.
When this button is clicked to send a post request to the
backend, to create a new order.
And for this, I'm also not going to send an Ajax request,
but instead I'll let the browser do that.
Here, my goal is to set an action like slash orders
and set the methods to post,
and we'll have to add a route on the backend that supports
post requests to slash orders.
And then that's already all I want to do.
You might be wondering where the form data is that should go
into this form.
But the answer is we don't need the form data here
because, we already have the cart,
which is part of this user's session.
And the session is already stored on the server side.
So in the route that handles a request to orders
we'll be able to look into the session
to see the cart of that user.
So the data that's in the cart already is on the server
side. So we won't have any problems working with it there
Hence, all we gotta do here is add a controller
that deals with orders.
So orders controller make sense
and add a dedicated routes
file. So in the routes folder,
I'll add an order as started routes Js file.
And then we can copy the cart routes into orders routes,
and refer to the orders controller here,
which we get access to by requiring dot slash controllers
slash orders controller.
And now we've got a couple of routes we want to define here.
For example, we want to add a route,
a post route to slash orders that will add a new order.
Now just as with the admin or to cart routes,
I will register the orders routes in app JS such that we set
up the prefixed there so we can ignore the prefix in
the routes file. Instead here in app JS,
we can add to the order routes
by requiring dot slash routes
orders routes
let's actually also named this
orders routes to be in line with that file name.
And then we can register this after protect route
middleware because order related routes are only available
if you are locked in. So after protect routes,
middleware I'll add app use
and add slash orders as a
prefix, and then point at the orders routes.
And because of this prefix here,
the routes in the orders routes folder will automatically
start with slash orders.
So this is slash orders slash nothing,
and therefore, it will become active if a post request is
sent to slash orders.
And then we want to point at the orders controller and their
a to be added action
A action that could be named
addOrder,
but the name is up to you.
You just have to make sure that you add a function with that
name in the orders controller and that you export it there.
So that's what I'll do here.
Add a function named addOrder here in the orders controller,
and then add module exports to export an object where we
have an add order key and point at the add order function
to make it available outside of this file.
And now in here, as always, of course,
we get the request and the response, and we can get our
cart which we need to place the order
because the cart contains all the data that's relevant
for the order
by accessing res dot locals dot cart.
That's how we get access to the cart
and we can store it in a cart, help or constant.
Now it's in the end that this cart data,
which I want to translate into order data,
which I store in a standalone brand new collection.
And for this, of course, we need a model.
We need a model a order dot model to be precise
in this order dot model JS file.
We can define the order class and then a constructor,
which we use for initializing order objects that are based
on this class.
I will also at the export to the order
So did I don't forget to do this again.
Now here, 40 order, we then need various pieces of data.
We need the cart, let's say,
because that contains all the product data we're interested
in.
We also need some user data like the email and the ID,
and maybe also the name and address of that user.
Otherwise it would be hard to ship that order from a shop
owner's perspective.
So I expect to get user data here,
which contains as I just said, email ID, address, name,
and so on.
I also want to accept a status so that if we are re
initializing an already existing order,
we can take its current status and otherwise I'll add a
default value of pending.
And let's say we have free possible status here that would
be pending, fulfilled, and canceled.
And initially at one pending here,
we'll later add functionality to change
it to other status as well.
Now orders should also have a date
when it was placed
and we might also get an ID. Of course,
initially we don't have one yet, but if we are,
as I said before,
re initializing a object for an order that was fetched from
the database, because we might want to update it.
Then of course we will have an order ID and then I want to
store it in this object. That's based on this blueprint.
So therefore now in this constructor,
I now will set my product data,
equal to cart
because that in the end is the kind of data
that is in the cart it's data
about the products we added there,
including the total amount and total quantity.
I will add a user data property here,
which is equal to user data
and set the state as equal to status.
And then regarding the date, all set this equal to new date,
where I pass a date,
a value to now new date uses the built in date constructor
function,
the built in date clause to construct a date value type,
which is a value type,
a kind of object built into JavaScript,
which gives us various utility methods for working with
dates.
And I expect a date here,
which we get as a parameter to be a string representation of
a date,
something like
2021
0 7,
um, 15 or 16,
and then maybe some time snapshot and that string
representation will be transformed into such a date object
with which we can work by this line of code.
Of course, sometimes no date might be provided.
For example,
when we first create an order and will therefore have to
ensure that we handled this properly,
when we then later a save such order to the database
Last but not least, I'll set this ID equal to the order ID
I'm getting here.
And actually, before I do that,
I want to add a formatted date field here
where I actually take my date that I have.
And therefore here, I will check if this state is truth,
but if I do have a date,
then I also want to add this formatted date property,
which I actually set equal to this start date
to local date string,
which allows me to format the date in a more human readable
way for this as a first parameter value,
we pass a low kale identifier,
like E N U S for American English,
which controls for which kind of language the date will be
formatted for which kind of region on the world.
And the second argument is an object with configuration
options where we can, for example,
say that we want to print the weekday in a short human
readable way, something like Monday, Tuesday,
and so on that we want to have the day off the month in
numeric version as a numeric number that we want to have the
month as a long output.
So that July is not written as 0 7, but as July.
And that the year should be numeric.
That's one possible formatting we could choose.
With that we are defining some settings
for how a order object should be represented in our code.
We of course also need to add a method for then actually
saving that data to the database.