Transcripts
1. Intro: This course, you will
learn about MRNSTeC in practice on creating a FlSteC
digital ecommerce website. Welcome. This is a class for everyone who
wants to learn about creating a FluSTeC
applications using MarnSTeC. It will give you a
great basics and understanding how Fluste
applications work. MRNSTeC is a group
of technologies that work together to build
websites and web apps. By the end of this
course, you will be able to add new data
from your website, straight to the database,
update them straight from your website,
and also delete. Don't worry if you
are new to this, I will explain everything
in simple terms, so it's easy to follow. Let's say that first 70% of
the course is learning MntC, learning how to work
with the data and HDDP methods to work
with your database. In our case, MongoDB
and the rest will be about utilizing this for a
digital ecommerce website. So in the end, you have
a nice working project. Let's see what these
letters stands for M for MongoDB MongoDB is a type of database where you can store
information for your app, like user data or posts. It keeps things organized
and easy to find, just like a digital filling
cabinet, for example. E in Express, which is a tool
that helps connect front of the website or user C to the back where the
data and logic are. It makes it easier to
handle things like routes, which are like
paths that lead to different parts of
our application, R in react, which is
a framework that is used to build a
part of the website that users interact with. It makes the pages more
interactive and dynamic. So when user clicks on
things or type in forms, the page can update smoothly
without needing to reload. Then in note, which lets us
use JavaScript on the server, which is the part of the app that works behind the scenes and it will help our app to do things like connect
to the database, handle user logins
and process data. We will be also integrating different solutions
for our needs. For example, stripe for payments and loadinary for image storage. We also deploy our site to
go through it together and learn how to deploy flustg application like
this to the Internet. Because we care about security, we will also use
something called JWT or JSON web tokens
to secure our paths that we will be using to
call this database and do these HDP methods as
post, get or delete. Looking forward to
see on the course.
2. Setup: First, we will CD
the Band folder. We will do Command NPM Y. We will go into package dot JSON and there below the description. We'll do a type with module, which will allow us
to import and export. And we will execute the
command you can find in the description for installing all the libraries we will need. In Backend folder, again, we will create a new file dot N for storing the
environment variables. We will start with the port
there and we will use 3,000. Now we'll create
another new file, and that will be
called index dogs. In indexed Dogs,
we'll start with importing the modules we will
need for the application. Express library for
building the server, config function from the tenth to load the
environment variables, Mangus for Mongo DB
Object modeling, course middleware to enable cross origin sharing,
Cloudinary for handling, Cloud Image storage,
Mlter for handling, file uploads, and Cloudinary
storage adapter for Mlter. This function, we will load environment variables from
dot N file, we created there. Then we will create an
instance of Express, and then on this instance of
Express, we will use course. That means we'll allow the
cross origin requests. You can imagine this as giving
a passport to our request. If we don't use it,
our request will fail. Now you'll start
the server and tell our app that it should listen to our report that we set there. It will be port 3,000. And also to know if
it's successful or not, we'll add a console log, and that will back
then that server running on and out board. Before we write, we
need to review things. Let's go to package JSON. There under script. There we can delete the test. And instead, we'll
write the start, node index to Js and also
def nodemon indexed to JS. We will CD acond now
we'll do NPM run. Deaf and you can see
our server was started, and also server running on 3,000 port was
shown in a Console. And now I'll show you what
is nodemon doing for us. So let's change this server
to server AA, save it. And now you can see the server got automatically restarted. And this is how it will work
even with other changes. Of course, we won't be
changing the console logs, but if you change
something on our page, then the server will
get automatically restarted and we will see
the change in real time.
3. MongoDB: Now we will set up MongoiB. So we'll click there
on their page, mongoib.com on try free. Then we will fill the data and we will create the account. Then you will verify your email, then we will go
there in the panel, and we will click on Database. Then we'll click on Create
we will select free. There you can change the
name for your cluster, and what is a cluster? Cluster is a collection
of multiple servers. Imagine we have a books
stored in a library, and instead of one library, we have it in multiple
smaller libraries. In case one is closed, we can access other libraries. In our term, that means that we will avoid the
server failure. Now, you click on
Create Deployment. We will select their
username and password, and then before we continue, need to click on this
Create database user. Then we will click on
Choose a connection method. Then we'll click on drivers. Then we have their selected
no JS, which is correct. We need to use NPM install
Mon goody B in our project. Then we will take
this string and we'll put it into
environment variables. Let's copy this, click on D. We'll go to VS code where we have folder
with our project. There we will do CD back end. We will do NPM I Mongo DB. Then in our Bond project, we will go into
environment variables. There we'll create MongoDB, equals, and we will place there the string
that we just copied. Now what you need to do is
that you need to change this for your password that
you set in the Mongo DB. Now we will connect to MongoDB using Mongoose and
lock success or error. After Mongos
keyboard, we will do. Connect. Then and catch. We'll try to connect. Then
if we are successful, we'll want to log also
next to server is running. Database is connected,
so we know it. And in case there are issues, we can see that the
database wasn't connected, and that we will achieve with
catching this error there. But if you will see
the first line, where we should connect. Now it's empty. So we
cannot do just MongoDB. We need to also do the
process dot environment or NO you can already see
we go there an error. But in this case, you just
need to restart the server. If you don't know how,
you will do Sutter plus C, Y, Enter. And then again NPM run Gap. Now if you run again, your
database will be connected.
4. Product Model: Now we'll tell our application to use a tool that
will automatically read and understand
JSON data that will be sent in
request to our server. So for example, when we will
receive JSON like this, we will be able to work with it. Now, let's create modules and routes and see
this in practice. So first, in our Ben folder, we'll create a new one and
that will be called Models. Then another one, and that
will be called Routes. In modules, we will start
with the file called product dot JS or
product model dot JS, and in routes, we will start
with product Route dot JS. First, let's start in
product model dot JS. We will import the Mongoose
to work with the Mongo D B. We'll create the product schema, and there we'll start putting the fields we want
for our product. First one will be name, it will be of type string, and it will be required. Next one will be price, and a stripe is accepting
the price in a sense, we will do it directly
in sense also, so it will be done easier. It will be type number and
also it will be required. For every product, we
will need an image, and this image is type of string because it's actually
an URL of the image. And how we will get this URL, we will get it via
the Cloudinary that we will configurate later. This field will
be also required. Next, we will create a
picklist named category. It will be of type string, and also it will be required, but we will have their anym
for course and template, and that will
create a pick list. And then we will export
this product schema. Now we'll start
writing the routes. First, we will import the
express to create a router and then we'll also import our product, which
we just created. Now we will create a
new router instance, and this will help us
to organize and handle different URLs or routes
in our application. For you to have
Context immediately, we will do Export
Default Router, and we will go into
index dot JS and there we will first import the product route
we are now working on, and then we will app use product from the
product drought. Now, when we will
create a new route for creating a new product
item with dot Post method, we will have there
this slash online. But we define there
this product route. So when we want on
front end to actually create a new item or in postman, we will need to call then the URL would look like
something like this. It will be Local host 3,000. Then as we did there, the
product in product route, it will be slash product. And there as there is
nothing, it will be empty. But we will specify before
for Excios or in Postman, that this is a post method. So it will automatically
know it's this route, and to have even
another example, if we do the create product, then the route will
look like this. We will put there recommend
that this route is for creating a new product
and we can continue. First, we'll do
Tricatchblock inside. So if our block from Tri fails, we will lock the error in catch. We will lock the
error in console log, and then we will set the response status to 500 and we will send
the error message. Now, to check if the
required fields are present, we will do if condition there. In case any of these
fields are missing, it will return a true that means it will fail because
then in the true block, we will set response status to 400 and message required
fields are missing. In case it's false and
we have all the fields, it will continue to this
creation of a new constant, new product where we
will set all the fields. Now with product dot create, we will save this new
product into a database, and then we will return
a response with two oh one and send the created
status with new product.
5. Postman & Product Routes: We'll go on postman.com and
we'll sign up for free. We will fill all the
informations there, fill more informations there. Then down on the page, you will click on Download
Desktop application, actually download
it and install it. Now on the page, we'll
click on new request, and there we'll work
with our requests. There we'll be putting
the endpoint URL, and there we'll be
changing the methods. So get post put and delete. We'll be using these four. Then we'll hit Send and we'll be seeing
the outputs there. If we will be sending some data, we'll be putting
them into this body, where we will select raw and make sure that is
selected also JSON. Format, how you are inserting data looks like curly brackets, then field and then value. And this field name
will depend on what we will define
at our model. So for example, for the name, it will be name and value John. And the URL depends
on the route you set. So we are using
their product route, which starts with slash
Product and then, for example, for
creating a new product, we are seeing their post
method, and that's it. We'll be calling local
host 3,000 product. And now, if we send, we have a route for get. That means it will get all
our data from Mongo Di B. Now to immediately
test our new route, we will go into Postman, there we will change it to post. We'll start with the local host, then we will do the product, and then we can
leave this empty. We will select their body, raw, Make sure this is Jason. First, we will insert your name, then price in Send
image with testing URL, of course, won't work and the category where
you have a template. Now as these are strings, we need to have the quotes, but for number,
we don't need it. Now let's try to hit Send
and we were successful. Now we can check our MongoDB, and in our MongoDB, this
record was inserted. Later on front end,
we will create an input form where we will
fill all these fields. Then we will click on a button
it will call this route, and it will get
inserted into MongoDB. Now to display our
products that we will insert into
Mongol B on our page, we will need to also get
a route for getting them. And now we will go one
by one and create them. For routes of getting all items, we will first again do
try catch block inside. We did find, we will retrieve all the items from our database, and we'll set status to 200, which is like O status. In case there will be an error, we will lock the error message, answer the response
status to 500, then we will go to
Postman to test it, change post to get, it sent, and we will receive
data from our database. Like before, we'll
do Router dot get, but now in a path, we
will specify also the ID. That means we will
in the path need to specify also this
ID we have there. And that we will extract simply from the request
parameters like this. Now we will find it by ID with
this function find by ID, and then we'll
send a response to 100 with the product retrieved. In case this fails, like before, we will log the error message, set the status to 500 and
send it. Now let's test it. So let's take the ID, put
it there, now send it. And we got the item. Now let's continue with
route for deletion, and it will be quite similar
to get product route. Instead of G, we will
do that delete method. Then we will also insert
the ID parameter, and we'll do Trakageblock. In wreckage block, the
catch will be the same, and in Tribloc we'll also first extract the product item
by the ID parameter. Then we'll find it with the
ID and we will delete it. We will do an if
condition there in case result is false and
the item was not found, and we'll return a response
with Satus four oh four, and then we will
also send a message with product not found. In case result is true,
so the product is found, we will skip this if condition
and continue and set the response status to 200 and send a message product
successfully deleted. Now we can test it, so we
simply change this two, delete. Now we will send it and
product successfully deleted. Now, we select
back the G method, and we delete the ID and leave there product and hit Send, you will see that we
have nothing there. But now if we change
this to post, we can do the test AA, send it. Now we can do again
get, send it. You will see that we again
fill there some data. We will continue with the
Update product route. In update, we'll be
using Dt Put method, and there we'll also specify the D of which product
we want to update. Again, we'll do a
tryCatch block. And this condition to check if we have
there all the fields, and we won't be updating
the product image. In case some field is missing, we'll send a message
with response status 400 required fields are missing. Then we'll extract the ID
from the request parameters. We'll find the product item and update it with new data
from the request body. Then we'll do an I condition, and in case this
result is false, we will return status four oh four with
product not found. In other scenario, we
will just continue set the status to 200 and
send the message, product updated in case the trade block fails
and we gauge block, will again log the message, set the status to 500 and
send the error message. Now in Postman, we have the URL with local
host product and ID. We'll change it to put there we will change
the test AA to test BB. Now we'll delete the image because that is something
we won't be updating. We will send it and we
got product not found. So that is because I
put there a wrong ID. We will change this to get. We will delete this.
We will hit Send. Now we will copy this ID from
the product we have there. We will put it there. Now
we will change this to put. Now we will have it like this. We will hit Send, and we will
receive product updated. Now, if you go back to get and delete this
ID and hit Send, you can see that
in our database, we have now test A B
instead of test AA, and we can also do post,
then leave it like this. There we can do test AA. We will put their
image URL test image. Now we will hit Send. Now
we will do also test CC. We will hit Send and
Test DD, hit Send. Now we will change
it to get method, hit Send, and you
will see that we have there all our test
records we put there. Now you can try all
these routes that we did get post, put, and delete.
6. Frontend Setup: And now we'll move to front end folder and start
coding the front end there. We can close these,
open a terminal, then terminal, we will do CD. Front end, we will execute
the tailwind commands you can find on telencss.com.
First one is this one. I'm putting there the dot, so the project will be created inside this
front end folder. Now I will run this
for the installation. Then this for the
initialization. Now, this one for
installing the libraries, you can find this
command in description. Now we will go into
tailwind conflict JS file. We need to paste
there this setting, we will need for Daisy UI and also, of course,
for tailwind. Also, to have the
correct typography, we will put the first
require tan CSS typography, and the next after this needs
to be require Daisy UI. Otherwise, it won't work.
You can do your own team. So there I put the placeholder for my team where
I choose primary, secondary accent and neutrlor. And we are also using
there some DaisyUI teams, which are light, dark, cupcake, forest or business. Then we'll be choosing which two to use for light and dark mode. Now let's start creating
folders and files. First, in the front end folder, we'll create a DdentFle where we also put
environment variables. There we will put Wheat, React app, backend, base URL, and we'll put there the
base URL of our backend, which is HTDP local host 3,000. Then in source file, we will create a new folder
and it will be with pages. Then another one, that
will be with context, then another one, and that
will be with components. In Index CSS, we will paste the three till
end directives. Then we can delete Abdo CSS. And in ABD Jasix, we can delete
everything and leave there just to return
with the empty fragment.
7. Protected Routes: First, before creating anything, we'll go into components and
we'll create a new file. The file will be called
Protected Routes. Do JS six. First, for navigation, we'll
import reactor router dome. Then we'll have a
function to check if the user is authenticated. Inside, we will return true if the token exists
in local storage. Otherwise, we will return false. Then we'll define the protected
route component itself. And we'll start with
the If condition. This if condition we'll check the mentioned is authenticated, and in case the user
is not authenticated, it will navigate him to
the login page when he can try it again and
login or register. In case he is and
this will pass, we will render the
children components, and on the end, we will export the protected
route component, so we can reduce
it in Abdo J six. In Abdo J six, let's
do these two imports. Then we will also import the
created protected route, and we will create
our first route inside the empty fragments. Everything in this
protected route will begin with
Admin and inside, we'll have the other routes. To have this a little
bit more clear we'll create a new constant
with admin routes. Now we can take it and put it
inside the protected route. So now all the routes
for our admin interface, we'll put there into
these admin routes. Let's start with the
first one. So let's go to pages, create
a new file there. It will be called admin.j6. There we will use the Snippet. We have there to export, so
we can go to Abdo J six, and there we can
start Admin import, then save it, check
that is imported. Also, what we will do there
is that we will route it. So route path slash
element like this, and now there we will
just close the tech. Now if we do slash Admin, and that's it because
there is nothing else. If there will be XIX, then if we do slash admin slash XIX, we will get to this
admin component. We still don't have the login
and register functionality, but we will do it a
little bit later. Now we will just go
to protected routes, we can just mock
it by commenting this and putting
there return through. Like this, it will
always return through, so we will be always
authenticated. But of course we
should put there to do implement login and
register functionality. Let's open the terminal, CD front end, do NPM Run Dev, and there you can see our page.
8. Admin Dashboard: Now we can add some
class name there so we can double check
everything is working. Now to fix few issues. We need to go into
Abdo GS six and wrap our route into outtak we will add this then we will
move into main do GS six. There we will import Browser Router from
React router Dome and we will change direct
strict mode and wrap our app inside
Browser Router text. Now, if we will go
on the URL with local host that we use
and do slash Admin, you will see our
tailwind is working and we have dio text
we have in our DIF. So we can go back to admin page. First, we'll import, use
effect and us state, also from react, then Exios and then Link
from React router Dome. We will use us State hook to
manage the product state. We will initialize it
as an empty array. Then we will use us State Hook to manage
the loading state, and this one will help us because then we'll be
using the loading, and in case it will be true, we will be showing the spinner. Now we will use
useffectHok to perform side effects in the function
component on our admin page. First, we will set
loading to true. We will make a Gad request to fetch the product
data from the API. You can think of Exiles
as a tool that allows our application to talk to
servers and get or send data. So our Exiles will
get something and then it will do something
or in case it will fail, it will catch the error. So this is the URL
that we were using in the postman now we will
use it there in Exis. So we will try to get
this URL API endpoint. In case we have a
successful response, we will update the product state with the data we received. And then we'll also set the
loading state to falls. In case we fail,
we will catch it, log any error, and then we will set also
loading state to falls. Then on this last line is actually an empty
dependency array, and that means this effect will run once when the
component is loaded. Now let's move to the
UI, there we can start. We will delete the
class name from there. We will add some padding
and maximum width. I can also add there
some background gray 500 so we can see where
we are on the page. So we can see we will also need to center
this with Mx auto. Now we'll add another div
because above this div, we will have still a stats component that we
didn't code yet. And for this div, we'll put the
overflow X auto class because we want to enable
the side scrolling. Then we'll add table itself, and we will put the class
name table because we are using Daisy UI and DUI have
a class for the table. Inside the table,
we will put a Thad, which stays for table head, TR, which stays for table rows, and now we are the table
headers of nine price, description, and
category, we have the first table header
empty because we will end a button that will lead us to a page where we'll be able to
create a new product item. So inside, we can put a
link with name at item. Currently, we still don't have the page for creation
of a new item, so we will leave this to empty,
and then we will fix it. I will set the green background, and onHver I will change the
background to darker green. Then I will send text
size and text color, some padding and border
radius with some shadow. Now we'll need to
do the table body, so we will make
there some space. Inside, we'll do a table body, and in table body, we will need to iterate
over the product. And now we'll code one
table row and it will get repeated every time it will iterate over
the product array. So in our table row, we'll
do the key as product ID, and then we'll start with the class name for background white, and when we will
hover over our item, we will change it to
a bit darker color, which is in our case,
background gray to 300. And now we'll be
just putting into this table row the table data, which will be accordingly
to the table headers. So on the first position,
we will have product image. So you can see there we are using DIV with
class name Avatar, which is from DSUI and then
another div with mask, also from DSUI some
width and height set. Then in image itself, we are setting source from
product dot image, and in case it won't be
loadable, for product dot title. We are getting all
this data from Mongo DV where we loaded them. In the next olume, we will show product dot name. You
can see it also there. Then we'd like to show
price description and category, let's do it. As price, we will show
price in a sense, then the description,
then a category, and that will be it for now. You can see I left the
description without mapping over the product and
that's because we didn't add description
yet to our model. I wanted to leave there
one field in case you would also want to add
one field for yourself. I will show you now how you
can add additional fields, we'll open the explorer. In back end, we'll
go to the models. In Barack model we will
there add a description. It will be of type string, and the required will be false because we don't need
to have this field filled, then we will go into
route product route. Now we'll scroll up to
create new product route. There in new product, we
will add a description, so description request,
but the description. And now we can test
it, so we will open Postman, and by the way, if anything is not
working for you, make sure you are always in a CD backend folder,
like now I am. And you have the
server running with NPM run depth because the database needs to be
connected all the time. So just check through these open terminals
you have there. You can see I have running the front end and also I
have running the backend. Sometimes what can happen, there is some issue error, and the backend server is down. So you need to check it sometime because otherwise,
it won't work for you. Now I will put there
some testing data even with the description field. Now I will hit Send and you can see it was
inserted like this. Now if I will change
this to get hit Send I can see that I have their items
without the descriptions, but my newest one is including the description
field that we just edit. So now what I will also do is that I will just
copy paste this, take the description, save
it, and now it will work. And now you can see on our page, all the items are loaded.
9. Delete And Edit Product: Pages, we will
create a new file. Edit product G six, also delete Product G six. Then we will use AFC, so it will use the snippet from the extension ES seven plus. There you can download it also. Now we'll go to AG six, where we will import
these two new pages. And also we'll route them. We will add its route to
the route of admin routes. Put the path where
it will be product, edit, or delete with the ID. In edit product, we will
start with the imports. First, we'll import
notice tech for the snack bar we'll
use for notifications. Then we'll import with react also the use state
and use effect hooks, react roterdm and also Eos. We will set the state hook for form fields and loading state. We will be updating the name, pricing sense, and category. And if you edit some
field, as, for example, the description, you will
edit there also like this. Description, set description, and the default
value will be empty. Then we'll do hook
for navigation. That means after we
successfully edit our product, it will navigate us to
the admin dashboard. I mean not yet, but we will use this navigate
function for that. Next one, what we
will do is hook to get the ID parameter
from the URL, and then snack bar. That means we'll be showing the notification
in case we will be successful or not successful
at editing our product. We'll create an
effect hook to fetch the product details
when our page loads. We'll start with setting
loading to room. Then like as before,
we'll use Exiles first, we'll try to get
the response from this endpoint where we'll
also paste this ID. If you don't remember,
in our product route, we set the ID as
needed parameter for the update product
route because we need to know which product
we want to update. Then in case we are successful, we will set the fields
value to the response. So set name, price incense,
description, and category. Then also, we will
set loading to falls. So after we will have a spin on there, it will stop spinning. In case this will fail, we
will catch the error there, also set loading
to falls, log it, and then send an alert
that something happened. And what about the
dependence array? Now it won't be empty, but we'll have their NID. And this means that this effect will run when the
ID will be changed. Now we'll do a handle for
editing the product item. First, we will
have their data to be sent in the Put request, then we will set
loading to true, and we'll have their Excise. First, we'll make put request
to update the product item. And then in case
we are successful, we'll set loading to falls. We will then show
the success message or the success notification, as you can see QsNCbr there, and then we will navigate
to the admin dashboard. So whenever this was
successful from this page, we'll be automatically
sent to admin dashboard. In case it fails, we will
have the error there. We will set loading to falls. We will send the
error notification, and also we'll log the
arrow into the console. And to get on our page where
we'll actually code DUI, let's go to admin J six. There had on the bottom, below last table data, create a new table data, put the class name for
the table data before. Now create your TV
with classes of flexbox layout so we can use
Justify Center for centering it horizontally and then gap X one to have there some gap
between these two links. We'll have the
link for the edit. Now, if we go through it, you
can see it using the path Admin product slash Edit and then it's also sending
the ID of the product. Remember, we are still iterating
over the products there. So we have the ID of the product
and we can use it there, and we'll send it to Path then
we have some class names, so we will use
background to orange and on Her we will make
it a bit darker. Then we will set text
white and font weight. Also, we'll make the
border radius there, text size there, and
use some padding. You can basically
just copy paste it because it will be
almost the same. Just in the path, there will
be delete instead of edit. Also, you'll change
the background color, and we'll change the text. It won't be edit, but
it will be delete. Now on our page, we will select some product
and click on Edit, and it will take us to the page where we are
currently coding now. So let's go to the page, and there we can start. First, in the main div,
we'll use some bedding, background gray to 50, flexbook layout, so we
can center the items. Then we'll do another div with container class
that is from the AZUI. We'll set some mix with the
shadow then border radius, bedding and background to white. And in case we would
like to go back, we'll use this link to B. So we'll put there to Admin, then in class name,
we'll center the B text. Set the background for
this button, some padding, so it actually
looks like button, margin with text size, and I border radius. Then we'll continue with
the title for this section. We'll name it Edit product. We'll set some text size
to it, from semi bold, vertical margin, and we'll set the text color to text gray 800. Now we will prepare the
di for the input boxes. So we'll do a DIF with
vertical margin to four. First input will
be for the name, so we will have the label
with the name and its input. In label, we'll do HTML four
where we'll put a name. For class names, we'll
put block, text medium, and text grade to 600
with some margin bottom, and for the input, we'll set
ID to name type of text. Value will be set also to name, and on change, we will set the name for the target
value we have there. For a class name of this input, we'll set some border, and we will set also
the border color, some padding, with the full, and also we will use some
border radius there. And now it will be basically the same for all
the other inputs. But some values will be
changing This HTML four, this ID, the type, of course, the value,
and the use state hook. So for pricing sense, we will change it
to these values, but otherwise, it will use
the same values as before. So same for description with
set description description, ID, and HTML four like this, of course, also with
the label text, for category, we will also add their options because
this is a pick list. So you have option
for select category and then curse and template. We will have the values
that will be set then there and read
by this use state. Otherwise, again,
everything is the same. HTML four is changed
to category, ID is category, value category, classes are the same, and we are having required there because we need to select
the picklist value. Also, this is not an
input but a select, so take care of this text. Then to confirm this edit, we'll have a button
there with safe changes. On a click, it will call this handle Edit product,
which we code there. Then we'll set our class
name of it to full. We'll set the
background to green, and we will use a darker green, then text to white, some padding and border radius
with some margin to top. Now we can test
the functionality, and then I promise we will
make the UI look better. So let's change TBB
to Test BB edit it. Then we can also change price in sense, description,
and category. Save changes. Now you
can see it got edited. And if we go into MongoDB, you can see it's
edited also there. Let's now go to files
there into Min J six, and there we will wrap our application into the
Snack Bar provider text. So there let's put our
application inside. Also, let's import it. So if we do just this, it will get imported
automatically. Now if we go back to our page, we can try again
to edit something. Now, we will leave
this field empty. We will save changes,
and you can see we received an error in case we will fill it and
we will save it. You can see the
successful notification. So again, main do the JA six, wrap our application
to Snack Bar provider, import it, and it will work. Now to finally set a team, we'll go to index dot HTML, and there in HTML tech, we will do data team to Light. Now it finally it looks better, and if we go to edit, you can also see it
looks good there. And now to the deletion part. Let's click there on some
item. Let's click on Delete. So we'll get to
the page VS code, we'll go to delete product.j6. First, let's do the imports
like before, then the hooks. First one for the loading state, Navigation, getting
ID from the URL. And the snack bar for
the notifications. Now we'll create a handler for
deleting the product item. We will set loading to true, and then we'll excise
with delete function, we will call the endpoint
to delete the product. In case we are successful, well set loading to fals
notification with product was deleted and navigate
ourselves to admin dashboard. In case it fails, we will
set loading to false also send error notification
and log the error. In the main div, we'll use
some pedding background gray, and then flexbox layout
so we can center the items with justify
and items center. Inside, we'll do another
div with class container, which is from the DaisUI. We will set some maximum
width shadow and pedding. Like before, in Edit
product GS six, we'll do a back button there. And as it is absolutely the
same, I want to explain it, and I will move to
the heading two, where we will ask, Are you sure you want to
delete this product? For this, we will set some
classes with text size, text weight, margin to
bottom and text color. And then the answer can be clicking on a button
with yes, delete. Otherwise, user will just
click on a B button. In case, user will
click on delete button, it will call the
handle delete product, which we did there. And class for this
delete button will be a red button with
darker red on Her, text white, some pading, border radios, and with to full. Now we can check it on the page, and we can try to
delete the product. Let's click on as Delete. You can see product deleted and also it disappeared
from our list of items.
10. Spinner: Now before moving to
create product GS six, we will create a spinner. Let's open the files there, and this one will
be in components. So in components,
create a new file, spinner dot JS six.
Use the snippet there. Now for this div, we'll
use a flexbox layout, justify items to center, and side determine
height to screen. For the next div, we will
set with anhight to 16, border with to four pixels, border style to dashed, round it full, so it's a circle. Animate spin, which we will create index dot
CSS in a minute. Then border primary, so we
will use the primary color, top of the border
color transparent. Now for the animated spin, we go to index dot CSS there
first with keyframes, spin, where we will use the
rotate 360 degrees, and then for the animated spin, where we will set the
animation for spinning, 1 second, linear
and infinite loop. Now, if we go to Edit
Product GS six and there in the return below the start of the main dith, we
will add the spinner. It enters, so it will get
imported and save it. Now, if we go onto our page, you will see the
spinner is there. You end it there only when
the page will be loading. So what we'll do is
that we will put there curly brackets
with loading. And in case that's true, it will generate the
spinner. Now I will save it. If you will save the changes, you can see the
spinner was there for a really short time because the save was
actually quite fast. Now we can add the spinner
also to delete page. So let's just copy this. Go to delete product. Let's edit there. Now delete
the last leather, hit Enter. That way, it gets imported. And from now on, we can use the spinner wherever we will
have the loading state.
11. Cloudinary: Before creating a UI
for adding an item, we'll need to set
up a Cloudinary. It won't be efficient to upload such big images into MongoDB, so we'll upload it into separate
storage like Cloudinary. We will get the URL, and in a string, we will
store the URL in MongoDB. Then we will access the URL and we will be displaying
the images on our page. Let's go to cloudinary.com. Click on Get Started.
There you will sign up. Then you can select
something there. Let's start. There
you will scroll down, click on View credentials, and then you will use
these credentials. We'll take this cloud name, API key and API secret. Go into environment variables, and there we'll
create Cloud name, API secret and key. You will paste there
all the values you have on your Cloud binary, and then we'll move
to media library, and there we'll find all our
pictures we will upload. Now, if we go to Index Dogs, we can start coding the route that will actually
aloud our images. Now we'll configure Cloudinary creentials from
environment variables. So first will be the cloud Name, API key, and then API secret. Now we'll add a Cloudinary
instance with this upload use. So we are making sure
Cloudinary will be accessible before the
next route that follows. So the storage and upload image. Now we'll configure
Multi storage to use a Cloudinary for
storing our images. We will do the
Cloudinary instance, and then we'll set
the parameters. First parameter is the folder for our images, which is images. And then we'll set
allowed image formats, which will be JPEG and PNG. What we are doing there
is that we are creating a parser that uses
moltorlibrary, which we are using for handling the file uploads and the
storage configuration is the object we set there to specify how and where to
save the uploaded files. Now, we'll create a route for uploading the image
to Cloud binary. We'll do this with post method, and the route will be
called Upload Image. We'll use a parser to
upload a single file, and then with If condition, we'll check if the
file is there. In case it's not, it will return status 400 with
no file uploaded. Then we'll create
a tryCatch block. And we'll create an If condition if we have the
path for the file. In case not, we'll return error with file uploaded,
but no path available. In case there is the path, we'll return the file URL. And then in case this
world wide Block fails, we'll catch an
error there, return a Status 500 with the
internal server error.
12. Create Product: Now we'll go to pages
and create the new file. Create product.j6. There we snip it. Then we'll go to ab dot JSix. There we can copy this, paste it there, type
there, create product. Hit Enter, that way
it gets imported, and there we'll
change the path to just slash product slash Create. Now we'll go to admin.j6
and there in at item, we'll add a link, and
that will head us to Admin slash Create. First, we'll do the imports, then we'll create
state variables for all the field we
have for our product. And now we also
at image preview. This means when we
load the image, we will see the preview of it on our page before we
confirm and upload it, and then also state variable for the loading to show the spinner. Then hook for the navigation. After we will be successful, it will navigate us to
the Advantage board and also snack bar for
displaying the notifications. We'll create their handler
for file input change. We'll create a constant for the selected file that we'll
get from the input event. We will update the image
state with the selected file, and then on the selected file, we'll do an Ils condition. In case we have selected
files, and this is true, we will create a new
file reader instance, and we will set image preview
to the file, we upload it. And what this read
as data URL method does is that it reads the content of the
selected file and converts it to an
encoded string. And also, we'll add
set image preview to null in case the selected file is false, so it's not there. We'll create a function to
upload a file to Cloud binary. First, we need to check if we have an image for uploading. In case not, we'll send the warning notification
with no image selected. In case we have the
image, we'll continue, and we'll create a
new form data instant and we'll append
to it our image. Then we'll create a Tricatblock. In Trblock we'll
create Upload URL, and you can see there the upload image route that we did in Index dogs for uploading
the files into Cloudinary. And we will send
the post request to upload the URL with
the image data. Now from the Cloud
binary response, we will get the SURL which is the URL for our uploaded image. Then we will cons overload the uploaded image URL so
we can double check it, and we will send a notification that the image was
uploaded successfully. In the end, we'll
return the SecuRL. So when we will call this
upload file function and it will be successful, we will get the URL from it. In case it fails, we will set error there
with notification, fail to upload an image. And now we'll do
the big function itself for uploading
all the fields, even with the image
for our product, and we'll call it
handlesafe product. We'll check if required
fields are filled, and in case we will
send a notification, please fill all the
required fields. We have the or operator, so in case that any of
these values are false, so they are empty, it will
send this notification. Then we will have the check that the price is
a positive number, and in case not, we'll again
send the notification. We are also setting the
new price constant because we are converting price
incense into an integer. Then we will set loading to true and we will use it
for the spinner eter, and we will create a
tryCatch block there. First, we will attempt
to upload the image. You can see we'll await the upload file,
which we have there. In case we won't be successful
and this function fails, we will get an error
image upload failed. In other case, if
we are successful, we'll continue there and we will prepare the form data
for saving the product. Then we will send a post request to save the product
with the form data, and in case we are successful, we will send a
notification about it and then navigate the user
to an admin dashboard. In case this dryblock fails, we will send a notification
about error and log it, and we'll add also finally
block where we will set the loading state to false to indicate that the
process is done. Now we will code JS six so we
can test our new functions. We will now be cheating a bit. Or maybe it's better to call it that we'll be smart developers. What we'll do is that we will
go to Edit Product J six, and there we will actually
take the wall J six. Copy it and put it into
our create product. So there now we have it. And instead of edit,
we'll put there create. Next thing, what we
do is that we will scroll down and this button
won't be saving changes, but it will be just saving. Also on click, it
won't call handle Edit product because we don't even have this
function there. It's only there, but it will be calling the
HandlesafPduct function. So we can just delete this
one word, HandlesafPduct, and if you will double
click there and do Satterf, you can see it's this function that we did for
saving the product. Now we need to include three more things, and
that is the image. So pretty similar to
this label and Input, we will create one for
the image like this, and it will be
actually the same. Label will say upload image, HTML four will be
image, ID image, type will be file, except will be image
slash and on change, it will call this handle
file change that we did. Then it will also be required, and one more thing we need to add there is the image preview. For that, we'll use
a similar render like we are using for spinner. We will check if image
preview is true, and in case it is, we
will generate this HTML. Where we will have a diff that will be wrapping the image, and source of the image
will be the image preview. You can again see image preview is our state variable there, and we are setting it in
this handle file change. We will set there and
mix with to full and height to auto, that's
pretty much it. Now if you want to double check, I will slowly go through it. But it is basically the same
as we have Edit product, but we add different on click
function for the button, image preview, and
input for the image. We need to fix a
small thing there. It's actually not admin Create. It's Admins product
slash Create. Now if you save it, we are now on our loco host with slash Admin, so we
are on the dashboard. We will click Adm,
and we'll get to an actual create product
form. And now let's test it. So let's fill the data
and upload some image. We'll hit Save. End product with image we saved and
uploaded successfully. Now you can see our new item. You can see the
image preview there. Now we can delete the old data. I created two courses and
one template, and by now, we covered all
create, read, update, and delete or also
known as rat actions. And it's time to show them
on UI for our customers.
13. Home: We will now delete this Admin, we will be coding
the customer facing. Now we'll go into pages, create a new file,
home dot JS six. We will use the snippet there. Now we'll go into Abdo
GSSix and there in routes, but not in the admin route, we will create a new
route for the homepage. We will put there this path
and also element home. Then we will import
the home we created. There we import effect
and State Hook and Eos State to all
the product items, and we will continue
to use effect Dook to fetch the data when
this page will load. We will make an HTP gut request to fetch the product data. That means we'll call this
endpoint with product. And if you remember, this
is exactly what we did in Postman to get all the products
we have in our MongoiB. Then we will set the fetch
data to the product state. And in case we are
not successful, we will lock any
errors to the console. And also, this empty
dependency array means that this effect runs once
when the page will be loaded. For the main dif, we'll set maximum weight to 1,300 pixels, and we will center
it with mix Oto. Also, we'll add some merge
into top and padding. Inside, we'll do another div
with class hero content, and this zero content
is a class from DZI. Inside this zero content, we'll do another div with
some maximum weight, and there we'll put a text
descriptions and shop button. First, we'll welcome
the users on our page. We will add the name of
the page into the Spentex where we'll add some different text color to highlight it. Then we'll include
there some text and the button that will redirect our user to a shop itself later.
14. Product Card: Now we will load all the
products, but for that, we'll create two
separate components that will keep our code clean. Let's go into the components
and create a new file. Product single card J
six and product card.g6. In product card, we'll first import product
single card because this JS six will be as a layout for all
these single cards. Then this component will receive a product object as a prop, and it will display
its information. For the main div, we'll
use a grid layout, and we will on large screen, we'll use a grid columns tree. Then on a smaller screen, we will use two grid columns, and on mobile
screen, we will use one grid column
that we don't need to define because
it's a default value. Then we'll set maximum
width of 1,200 pixels, some gap between the items. We will center this
with mix Auto, and we also center the items
with place items center. Then we will iterate
over the products. And for every
product, we will call the component
product single card that we will code
right after this one, and we will input key with item ID and product
with the item. Now in dc.com, we will go
into the card on the panel, and we'll select there
a card that we like. Then you will select the J six
and you can copy the code. Then insert the code into this return on our product
single card a six. Also, don't forget to put
there a prop of product. To have all our images for
products nicely aligned, we'll set there to full, set there some fixed height. Also set their Object to
cover and object top. Also, we will set the source
as product dot image. Old as product dot name, and then to the card body
and the description, we'll set card title
as product name, then the description, and in case the description
won't be available, we will display no
description available, and then for the price, we'll divide it and
show it in dollars. So currently it's in cents, and we can convert it like this. It's also possible to have
some number format and use it. Now we'll do it in
more simple way. Then we'll head
to home Jasix and there we'll start
writing product card. Hit Enter that way,
it gets imported. Then we need to set
there a prop which is Product as product, save it. And then if we go to our page, we will see all the items we edit into our Mongo DB there. Now, everything we will edit, delete or add there on
the admin dashboard, you will see it also on
the customer facing there. So let's go to this
item. Let's edit it. Save changes, go back
to customer facing, refresh the page, and we
can see the change there. Now let's try to add an item. And now we can see it
on our customer facing. And now we'll create a card. So we are able to add there the products we want to
buy and then check out. For a card, we need to add navigation bar. So
let's go one by one.
15. Navbar And ThemeToggle: A two components. The create
a new file, nowbar.j6, and there you'll
use the snippet, go on ap J six and
edit above brutes. So there now bar, import it. You can head to daisy.com and select there on
Navbar you like. I go to J six, copy it
and paste it on my page. You will paste it
there, but I have a modified version, and
I will go through it. But before going through it, I will show you what I
actually imported, and we'll just need to import the link for the smooth scroll. We will use this link tech. Instead of the anchor
tag we head there. Now, to have this
navigation bar complete, we need to create
two more components. First one, which will
be Team tagle button, Chasix and second one, which will be card icon six. What we'll do in Dem toggle is to import use state and usefect. Then we'll define
a state variable for the dark mode
and continue with usefecdok to set
the initial team based on current team attribute. We will get the current team from the documentary element. You can see there data team, and if you now
remember and go to Index HML is the
one we set there. We'll set is dark mode state
based on the current them. Then we'll need to do the
function for tagling the team. So we'll name it
TagleTm and we'll make the new team based on the
current is dark mode state. So in case the dark
mode state is true, it will be cupcake team, and in case it's false,
it will be business team. Then we will get the data team and we will set
there the new team. And also, we'll toggle
the Is dark mode state. Now, we'll use
this toggle button that you can find
on the DCUIPage we will use Is dark mode for checked and Toggle
Team on change. Now, if we will go
back to our Navbar, we can add the Toggle
team button and then put it there into
the Div Navbar end, which is also from DZUI and
there we need to import it. So let's do it like
this. Save it. And now we will check our page. It's there, so let's
try to click it. And you can see it's
changing the team. And now, if you go back to VS
code in Team toggle button, you can set the teams you would like for light and dark mode.
16. Cart: Now let's call the
Card icon J six. On DCU icon, if you go
into the NaF Bar section, you can see that there
is enough bar with a card and if you
go into Ja six, we can actually take
the card from there. We can paste it
to our card icon, but we will need to
add a few things. First, before coding the wall card context and
this functionality, we can just mark it
by setting there a constant of total
quantity to zero. Then we'll wrap this dip into
a total quantity check with a condition that this
will be rendered only if total quantity
is above zero. Also, we'll add a total
quantity there and there. If we'll go back to
our navigation bar, we can add the link
to a card icon. Don't forget to import it. For the path, we'll
do slash Card. Let's create in pages
new file, Card J six. There we can do the snip it. Now we can go to Abdo J six. There we will edit to routes. Don't forget, we
need to also import it and the path will be card. Now, if we go on our page, you can see there the card
and when we will click on it, we will get redirected
to the card page. Let's jump to the total
quantity for a while now. If we go back to
card icon and change this total quantity to
five and save it now, you will check our page, you can see that the number
was shown there. Let's go to Context and there
we'll create a new file. That file will be called
Card Context. Logistics. In card context, first, we'll import also the hooks, and then we'll start with
creating context for the card. We will use a custom hook
to use the card context. We will set children as a prop, and we will wrap it
with the card context. Inside, we'll create
a state to hold the card items that will be initialized from
the local storage. Local storage is a feature that is provided
by web browsers. And it allows us to store the data locally on
the user's device. That means we will send to local storage the product that
the user will want to buy, and then in the card provider, we will load it from
the local storage. We'll create the use
effect to update the local storage whenever
card items state changes. There we will set it and
in dependence array, we will put the card items. Whenever it will be changed, we will update the
local storage. We'll create a function to
add an item to the card. For the set card items, we'll create a constant item in card and we'll try to find. Then we'll create if condition to check if the
item is already in the card. In case it's there, we will
increase its quantity by one, and in case not, we'll just
it with quantity of one. Then we also need
to have a function for removing from card. Then we'll again set card items, which is the state
defined there, and we'll just
decrease the quantity or remove the item if
the quantity is zero. Also, we will have function to decrease the quantity
of an item in a card. There again, we use the state. And on iterating
over the prep items, we'll be decreasing
the quantity, and in case we get to zero, we'll again remove it. We will also function
for clearing the card, and there we'll just set
card items to empty array, and also we'll remove them
from the local storage. In return, we'll provide card state and functions
to children components. In the values, we'll paste
all the functions we did, and it will wrap
the children prop. Now, we need to go to Mindjsix. There we will add
a card provider, and we will put our
application inside. Now the card provider is
wrapping our application. It's imported there, and we
will have the functionality. We can go to cardicon J six. In card icon, we'll ds card
context and import use card. We will use the used
card hook to access the card items from
the card context. And instead of this hardcoded
five we have there, we will calculate
the total quantity of items in the card. Now to add the ad to
card item functionality, we'll go on to
product single card. We will import our
used card hook from the card context to interact
with the card state. We will extract adds to card, remove from card
and card items from our use card hook we created
in the card context. We will find the item
in a card that matches the current product item and
save it into item in card. Then we'll get a quantity
of the item in a card, and before it will be zero, if the item won't be there, we'll create a function for
handling the adding item to the card and also function to handle removing the
item from the card. These are the functions
that we did there. Into product single card, we'll add the disk with
card actions from the ZI. We'll do a check
on the quantity. If it's above zero, in case it is and we have the
product in a card, we'll have removed
from card button. On a click, it will remove
the product from the card. In case the quantity
will be zero, it will render this add to card, and on a click, it will
add the item to the card. And now we can test it. You can see it gets edited
or removed from the card. So now I will click
that add to card. We have there one I will add also this
item and this item, and our number with
quantity in a card is increasing or
decreasing depending on how many items
we have in a card. And now, when we'll
click on the card, we will code the JS six. Let's go on to created
card J six page. First, we'll do the imports. Then we'll extract
the card items decreased card item quantity, and edit the card from
our use card hook. In case our card will be empty, we want to show a message. Your card is empty. So
we'll adare if condition. And in case our
card items length will be zero, we will
show this message. Also, before clicking on
Checkout for the stripe, we would like to know which is the total price of the
product we have in our card. For this, we will create a
new constant, total price, and we will count
there the total price of the items in our card. And then before creating a
handle checkout function, we will create J six. For the main day we will put maximum width of 1,400 pixels, center it with MMX Auto, put there some pedding
and margin from top. We'll put there heading
with shopping cart, set there some font weight, font size, margin
and text to center. Then we'll create the DIF
with a grid layout and set there similar grid columns like we have on a homepage, and we will iterate
over the card items. Each card item we'll show
in this div where we will have this key index and we
will show the item image. Then also, we'll
show the item name and its price which we will
convert to US dollars. Then we'll create a
DIF that will show the quantity of the item
we currently have in our card and below in
another DIF we will have the button for remove in case we want to remove
the item from the card. Last thing that we will
add there is a div that will hold paragraph tech
with total price again, and a button proceed
to checkout. After we'll create a function
for handling the checkout, we will add there
to this button, but for that, first, we need
to implement the stripe. This is how the page will
look like when it's empty. And if we now go back to home, add there some products
and go to card, you can see there, we
have the total price and also both products. Now if you click on remove them, we can remove them
from the card, and when there's nothing, it will again show
your card is empty.
17. Stripe: Go to stripe.com page, and we'll click
there on Start now. You will fill there your data and click on Create Account. After you will
verify your email, you can click there
on Explore features. If you don't want
to see this now, you can click there and
leave there on this page, we will click on developers. There we will click on API keys. There you will click
on Reveal Test key, then you will click
on it, and it will automatically copy
it to clipboard. We will head into Bend folder, and we'll save it there in
our environment variables. Create a new one under stripe secret key
and paste it there. Now we'll open a terminal. We will see the front end. And there we'll do NPM
stripe slash Stripe Js. We'll install this library. We will import it in
our card dot JS six, and there we'll create the
constant stripe promise with this load stripe function, and inside, we'll put
the publisher black key we have there in
our stripe account. First, we need to create the
route for checkout session. We will go into our Ben folder. In routes, we'll
create a new file, StripRut dot JS,
and then Index DJs, we will use this Stripe
route b dot slash Stripe and StripeROut. And we didn't import
this strip out yet. So let's go on the
top of this file. Make there a new
import from the route that we just created and
call it a stripe route. Then we have everything
in number indexOJS and we can go into Stripe
Route and code it there. We will import stripe, Express to create the router and a config from the tenth to load the environment variables. Now we'll load them
with this method. Then we'll create a new
router instances and we'll initialize stripe
with a secret key that we saved into
environment variables. And on the bottom of this route, we'll export the router to be used in other parts
of the application. And now we'll create the
route for a checkout session. We'll extract the products
from the request body. Then we'll create line
items for each product. We will set the price data
and product quantity. For price data, we'll
set the currency, and then we will set the name of the product and we can
also preview the image. Then for the unit amount, we will set the product
price in cents, and on quantity, we will
set the product quantity. Then we'll serialize the
product details for metadata. We will set there again, product name, product dot quantity, and product dot price in sens multiplied by 100 to
create the dollar value. Then we'll create a TIG
block and in the Tide block, we'll try to create checkout
session with stripe. For the session, we'll need
to set multiple parameters. First, we'll set card to
payment method types, then we'll set the line
items that we set there. Then we will add
product details to metadata that we
seralized there. We will set a payment mode
Make billing address required, and then we will set a
success and cancel URL. Currently, I will set
there local host 5173. Where is my front end running. But for this, we'll
need to create a component for success
and cancel options. And then set there its path. After this checkout session, we'll send the session
ID as a JSON responds. And if there's an error in
a catchblog we will log it and send the Bd request
status with an error message. Now to show you how to create the success and cancel page, we'll go into pages. There, we'll create a
new file, success.j6. Second one will be cancel.j6. We'll put there just a template. Now we'll go into eb.j6, and we will add these
two new pages into routes and put there a path
of success and cancel. Also, don't forget to
import these two new pages. And now we'll go
into B end folder, go there in the
environment variables, and there we'll
create the new one. And we'll call it
front end URL and Titer our local host 5173, where is our front end running. And then for the success URL, we'll put this environment
variable with success, which is the path for this page. Also, it can be done like this, but it's better practice
to put the environment variable with the front
end URL as it can change, and then we don't need to change all the paths in our code. Let's again double
check the stripe out.
18. Cart Checkout: And now in our card J six, we will code the handle
checkout function. First, we'll initialize
the stripe and we'll await stripe promise
that we did there. Then we'll transform card items into the checkout session, and we will load there
the necessary fields. Then we'll do a Trikagblock.
Inside the Tri Block. We'll make a post
request to create the checkout session with
the transformed items. Then we'll redirect the
stripe checkout page using the session ID
from the response. Now we'll check if the error
is true and in case it is, we will log it and send
a message into Console. Then if this wall
try Block fails, we will log any errors that occur during the
checkout process. And now don't forget to add
handle checkout function to OnClick on our button that
will take user to checkout. I will click there on
Pros Checkout in my card. And it will redirect me to page. Now we can test the Cencl
so when I will go back, I will get redirected to CenclPage where it's
currently nothing. Now we will fill the data
and we'll click on pay, and we will be redirected
to a success page.
19. Cancel Success Page: Now on our success page, next to displaying a message
that payment was successful, we'll be also siting our card item because after
user bought the products, there's no reason to
store them in a card. So we'll also seffactHok and use card custom hook that
we created in card context. First, we'll destructure the
clear card function from useCardHok and then we'll
create the use effect hook. We can console log that the
payment was successful, and then we'll call the
clear card function to empty our card.
Now we can test it. Let's add something to
card, proceed to checkout, pay it with Link, and there you can see
the card go reset. And we can also leave this
dependency array empty. So this use effect will run only when this page
will be loaded. Now, let's add some
styling to it. So first, let's enter the items. Let's add some in
height to screen. We can use background base
100 text based to content, then add some shadows, text
sizes and backgrounds, and the page will
look like this. Now we can code also
the Cancel page. So let's get on the page now. Let's proceed to checkout
and let's cancel it by just going back that will
redirect us on the Cancel page. Now what we'll do,
we'll just take the JS six from Success page.
We will paste it there. We'll put there
payment canceled, and we'll put there your
payment has been canceled. Please try again or Contact support if you have
any questions. Now, if you'll save it
and go on the page, you can see the output there.
20. Shop: Let's make this
shop button work. So we'll create a new page. We'll call it shop Dot JSix. We'll snipe there and
we'll go into Eb do JSix. There we'll include
it in the routes and also we'll import it. If we go to our homepage, we'll make our life easier
by changing this button to an anchor tag where
we will set HRF to shop. Now on our page, we
click the button, it will redirect
us to slash SHOP. And there we will code the page. We will Improduce state
and use effect hook, Exiles and product card
that we used on homepage. We will create
state variables for filtered products category,
and product itself. Then use effect to fetch the product items
from the server. We will make an HTP request, get put there the route
for getting the products, and with response, we will set the product state and
filtered product state. In case it fails,
we will log errors. Then we'll create a function
for filtering the products. Will do F condition to error in case product
is not an array, then we will create a copy
of the product array, and in case category
is not empty, we will filter our products
based on a salted category. Then we'll update the
filtered product state with a filtered product, and we'll create use
effect that will call this filter product function whenever product or
category will be changed. For J six, we'll create the
main div that will have a maximum width of 1,300 pixels and center
it with a mix auto. Inside, we'll do a div that will hold the picklist value
selection for category. We'll put there a label with category and the
pick list itself, where we will be
setting the category, and in our case,
the options will be all curses templates. Then on change there, we will set the state variable value. And last but not least, we'll put there
the product card, and we will send there
the filtered products. And now let's go on our page, and we'll select courses. There we have only two
courses that we created, and there we will
have a template, and that's it for our shop page.
21. Footer Subscriptions: To add a footer for our page, we can go on DZUI and select
the one that we like. Then in components, we'll create a new one and we'll
call it FuterGsix. There we is the snippet. In Abdo J six, we'll
import it on the bottom, so below the routes
because it's not routed. Import it Click on
JS six and copy it. I will paste it into
my footer on J six. Then I will go back,
take also this footer. I will mix it with
the one I just edit. So for the one I edit,
I don't need the legal and I don't also
need the services. Instead, I will put
there the footer I took. Save it. Now we'll check
how it looks like. As this is not our logo, we will put the H two
with name of our page. So text size. Then we can delete this put there different ear. We can leave this as this.This also and now for newsletter. We'll go into Bend folder in models, we'll create in file, subscriber model dot s. We can copy paste product
model, put it there. Now we will update the fields, and there will be just email of type string required True, and we'll put there
also unique True. Then we need to rename this. So this will be
subscriber schema. Take this, put it there, subscriber now we'll
go into Index dogs. Then we can copyat
Stripe, put there. Subscriber, change it
to subscriber route. In Route, we'll click on new file subscriber
route dot js. We can check how it's done in the product route dogs
if we don't remember, and we'll redo it for
subscriber out also. So there we'll have imports with the subscriber model that we created Express to
create there the Router, and we'll export it. Then now we'll finish
importing it in Index dogs. We can copypate the
Stripe route and we will put there instead
of it the name for subscriber route and also we'll import it from the subscriber
route we have there. We will create a new route for posting subscriber
to our MongoiB, we will extract the email
from the request body. Then we'll create RChbok and we will create a new
subscriber and call the create on
subscriber model with the input of the extracted
email from the request body. In case we will be successful, we will set the status to two oh one and send there
a new subscriber. In case not, we will
set the status to 400 and send an error message. In Index DJs, let's
double check and make sure we are using
the subscriber route. Now in Postman, we can test it. So there we will
select a post route. We will input there
our local host. We are using SAS subscriber, we select their body, raw JSON, we'll input their testing email,
and we will hit Send. And now we have it
there. We can also double check it and see
it in our database. And now we can go
back to Footer and create their function that
will call this endpoint. We will import also use state, and we will create a
state variable for email. I handle subscribe, we'ate we'll use this prevent default
form submission behavior. In a normal scenario, when
you will submit a form, the page will start reloading and with this prevent
default, it won't happen. Then we'll do a trackage block. We will send a post request
with the email as a payload. Now also before we end this, we need to send
some notification. Let's import there U Snack
Bar from notice tag, use there the snack Bar hook, and we can show success
notification with clearing the email from the input box that user put there. In case this ride block fails, we'll log the error and send
a notification about it. Now let's move to the
bottom of the page. And there we have the
subscribe button. For the input tech,
we'll change type to email and we'll also
set value to email, and we'll make it required so
user cannot just subscribe without filling an email at their unchanged that will
set our email state. We will set type of
our button to submit, and the main thing to our form, we'll add on submit and call this handle subscribe function that we did. And I did
the type of there. I'm not on local host 5,000, but it's 3,000 and we
didn't import Exiles. So let's fix it by
importing it now. And indexOJS, we are not using
subscribe but subscriber. So now we can fix
it by just dding there R at the the value of
email, we can subscribe. And now we subscribe
successfully. Email got reset, and in our Mongo Dib we can
see the new email. I would do that one more
thing. Instead of company, I would put their support. I would put their
email. In some cases, we can put there
also a phone number and we can delete these
two Anchor texts.
22. Stats: Now we'll create
stats component. In components, we'll
create a new one, stats.j6, go on to admin.j6, and we'll addi their intermeddv. We will import it. We will import use effect
and use state hooks. Then we'll define
the state variables for stats and loading status and we'll create
use effect hook to fetch the stats when this
component will load. We'll create an
asynchronous fetch stats function,
do a tricagblock, make a good request
to fetch the stats, and there we'll put an endpoint, but we'll do it after
this component. We will check if the
response is okay, and in case not, we'll
send there an error. Then parse the JSN response and update the stat state
with the fetch data. In the end, we'll set
loading to falls. If there will be
an error, we will log it and set loading
to falls also. Then to start the data fetching, we need to call this function. Dependency array will be empty, so this use effect will run
after the component loads. Then to see our data
in a correct format, we'll use a format currency
where we will send the value and we will get
rid of the digits number. For JA six, we'll create a grid layout that will
use three columns. On mobile screen, it
will use just one. And inside, we'll put
these text boxes from DZI. Well input there the
available balance, pending balance, and
total purchases. We'll check the loading state, and in case it will be loading, we'll put there loading
message, and in case not, we'll put there the
available balance or the total charges. Now, you can see it already on our page if you do slash Admin, but we don't have anything because we didn't
code the route yet. And now we will code it. We don't need to
create any new one. We'll just go into Backend
folder and then stripe JS. It will use the Get method. We'll put the path of
slash API slash Stat. We will do Trcchblog we will retrieve the account
balance from Stripe. For the bugging, we can
log in inter Console. Then we'll extract the available and pending balance
amounts in USD, and we'll need to convert
it from cents to dollars. Then we will list
the charges from Stripe and we'll get the
total number of charges. We will send the balance and charges stats as JSON responds. And in case it fails, we will lock in errors in catch block. Now as we have the route and
we can use the endpoint, we will go into stats and
there we'll insert it. It will look like
this, and now if we go on page in admin dashboard, you can see the
values got changed. But for the balance, it's a bit different because the values
are actually correct. But as we are using
test data in stripe, many are not loaded
into our bands. And now we can
hide the footer on our Admin dashboard, so
it will look better. We have already imported
their use location. Now we'll use it there
and also use constant is admin route and
check the path name starting with slash Admin. Then we will put it on
the bottom of the page, and we'll return
the operator there. In case this admin
route is true, we will show nothing, and in case it's false, we
will show the footer. Now, if you will go on the page, you can see that footer disappeared from our
admin dashboard, and if you go onto the customer facing, the
footer is still there.
23. Jwt: And now it's time to
secure the endpoints. JWT is commonly used for authentification.
How this will work. When user will log in,
which we will also create, the server will create a JWT or JCN webTken and it will
send it back to user. Then the user or Admin, will include this JWT in
headers of the requests. This will allow the
server to verify the user without some need to query the database each time. In our Bend folder, we'll
create a new folder. And we'll call it middleware. In this folder, we will
create a new file. Of middleware Js. Now, we'll go to environment variables and
we'll create a new one, which will be called JWT secret, and there we'll generate
our own secret key. How we can do it is that
we will open a terminal. We will pace there this command. And it will generate
the string for us. Now we'll take it, put
it into JWT secret, and we can continue
in our middleware. First, we'll import Config from the ten and also JWT
from JSN WebTken. Then we'll call Confit method to load the
environment variables, and we'll create a
middleware function to authenticate users using JWT. We'll retrieve the authorization
header from the request, then we'll do a check if the header is missing or
doesn't start with better. And in case not, we'll send a message with no token
authorization denied. Then we'll extract the token from the authorization header, and we'll do the verification
in a tricachblock. There we will verify it and save it into a decoded constant. We will attach the decoded
user information to the request object and we will pass control to
the next function. In case this fails, we will log the errors in catch and on
the bottom of the file, we'll export it as off. Now we'll go to
product route dot gs. There we'll import
this authentication, and we'll specify the off as the second argument
there in the post route. We will now put it also into delete route. And update route. Now, if you will try to update
the product, it will fail. Let's now create
login and register so we can actually pass
this off middleware. First, in models, we will
create usermodel dot js. We will import Mongoose
and create user schema. For user, we'll need email,
which will be type string, required and unique,
and also password, which will be typestring
and also be required. Then we'll export
this model as user. Now, we'll create a new folder
and call it Controllers. Inside, we'll do a new
file of controller dot JS. We'll import the necessary
modules and libraries. We will create a new
router instance, and we can start with route
for user registration. In Tricagblock, we'll extract email and password
from the request body. Then we will check if the
user with given email exists. And in case, yes,
we'll set status to 400 and send a message
that user already exists. Then we will has the
password using B crit, and we will create
a new user instance with the email and
the DHHedPassword. We will save user to database, and we will generate a JWT token and set
expiration to 1 hour. Then we'll send a created status with a token and
success message. In case this fails, we will
catch and log the error. We will continue with route
for login in Tricagblock. We will extract email and
password from the request body. We'll try to find the
user with a given email, and in case it doesn't exist, we'll set the
response status and sent a message with
invalid credentials. Then we'll compare
the provided password with the hashed password we are storing in our database and use if condition and in case it's true and the password
is matching, we will create the payload
with the user ID and email. Then we'll sign a JWT
token with payload, secret key, and expiration
time for 1 hour. Otherwise, we'll return status 400 with message
invalid credentials, and in case this drive block fails, we will lock the error. Also, we'll export
it as Afouter.
24. Login Register: Now we need to create
login and register form. Let's go into front
end folder pages, and there create a new file, Log in D J six and another
one Register DJ six. We will use this nippeS there. Then Abdo J six, we'll
route it like this. We'll put there a path
of login and register, and we'll also import it. In register JA six, we'll import necessary
modules and hooks. We will be using
Use State Hook and also link and use
Navigate for navigation. For making HTD P requests, we will import Exis. We'll declare hook
for navigation, and then we'll initialize
variables for user data, and we will set
their name, email, and two passwords
for confirmation, and default value will be empty. We will continue with state
variable for status message, where we will load error or success message in case
we will fail or succeed. He state variable for success
is a flag that we will use for displaying
the message on Y for the error or success. Default ly, we'll
set their falls. Then we'll do handler
for input change. And there we'll update the user data state
with a new input value. Also, we will clear
the status message and set our flag to falls. Then it's time for the
handler for form submission, and to prevent the
default form behavior, we will use prevent
default method. That means submitting the
form won't reload the page. Then we will check if the
confirmation password is same as the first password. This will be handling
the error scenario because we have
the not equals to, and we will set the
state variable that we are using as a flag to falls. Then we'll set status message
passwords don't match, that we will also display on UI in JA six, and we will return. Rest of the functionality, we will wrap in Tricag we'll make configuration
for the Es request, and for the headers, we will
set content type to JSON. After we will send
the post request to the register endpoint
with the user data, and this is the endpoint that
we coded in our controller. We will also attach config
with the headers to it to inform the server that
the reckless body contains JSON data. And after we manage
to post everything, let's set a success to true, then display the status
message with the registration successful and then navigate
the user to login page. In case describe block fails, we will set a success to false and we will send
an error message. Now to JS six itself, we will use the Flexbox layout with flex direction column, so the inputs will
be below each other. Then we will center the items with items center
and Justify center. We'll set Mnheiight to screen, and we'll set some
light background. We will create
heading for our form, which will be register and now to the displaying
of the status message. We will check if the status
message is true or false. In case it's true and some status message is actually set, we will render it, and we will render it in
paragraph tech, and then we'll just
play with the color. We need to check is
success variable, then use ternary operator, and in case it's true, we
will set it to green color, and in case it's false, we
will set it to red color. Way we will get the registration successful in green,
errors in red. Now, to the form itself, we will add there on
submit that we did there. And now we will insert all
the inputs for user name, email, and both passwords. For the first input, it
will be of type text with placeholder user name
and name set as name. Value, we will set
userdata dot name. This is from the state variable
that we defined there, so user data dot name. And on change, we'll call
the change input handler, which is the first
handler that we did. Then for classes, we
will set some shadow, border radios, with to fool, bedding, and gray text color. Now, we can copy paste it, and we'll set that
type of email, placeholder to email,
name to email, and user data to email also. Otherwise, it will be the
same for password as well. But again, the type, placeholder and name will be different. For value, we will again want to set stay variable
for a password. Then for confirmation
password input, we'll just add confirm
password two for the name, and in user data, it's
also called password two. Then a button for
submitting the form, so we will ada type submit. Then we can select the color
for the button on however, let's use some darker
one, text white. We can increase the font weight, bedding, border radius,
and with two full. That's it for the
form. Below the form, let's add some
additional text for asking the user if he
has an account already. And in case, yes,
he can click on sign in link that will
send him to a login page. We will go into Index DGS. There we'll do Abdo
use for off router. Now you move to the
top of the file. And we'll import the
router as of router. This is how the page
will look like. Let's input some test data
and click on register. So we were directed
onto a login page. And in database, we can
see under the users our newly created user with
email and hast password. For login page, it will be almost the same as
in register page. We will do the Imports there, declare a hook for navigation, set state variable
for login data, with default empty values, set state variable
for status message, then start with handler
for input change where we'll start with
updating the login data state with a new input value because
this will be called on our inputs that we will do in case status message is there, we'll reset it with setting
there an empty value, then we'll do the
submit handler. We don't want to form
to reload our page, so we will prevent defaults. Then we'll do a wreckage block. And we will send
the post request to the login endpoint
with the login data, and we'll also log it. Then we'll save the received
token in local storage. This is the JWT token,
and after we log in, we'll have it in
our local storage, and we'll be able to use the
page as the locked users. After the token will be deleted
from our local storage, the page will see us
as the unlocked users, so the functionality for locked users won't be there for us, or any functionality
that is behind authorization for JWT won't
be accessible for us. Then after everything
is successful, we'll be navigated
onto admin page. In a catch block, we'll create if condition to see
which error type we got. In case it's response, we'll set status message
with the response error. In case it's request, we'll console log the error request. And otherwise, we'll
just log the error. For J six, we can reuse the
UI that we used in register, but we will have
there less inputs. Heading instead of
register will be login. Again, we'll render
status message in case the status message
variable will be true, and then we'll render it in paragraph tag only with a
red color because for login, we'll be redirected
to an advent page, so there won't be any time for seeing the successful message. Then we'll create
tech for reform, and on submit, we'll
call the submit handler. Now we can copy PACD inputs
from Register JO six. We'll start with the email one, but we'll change
the value to login data dot email that
we defined there. On change, we'll call the
change input handler. Then for the other
input, it will be on value login data password. Then as a submit button, we'll create their login button, blue background, and on
how we'll use darker blue. And also on the bottom below the form itself, we
will add a text. No account yet, and in case
user won't have account, can go on the register
page with this link. Now it's time to test it, so we will click there on sign in. Now I will use the
password I set. I will click on Login
and it log me in.
25. Admin Navbar: I will show you how you can
create an admin nav bar that will be shown only after
login to admin dashboard. On this navigation
bar, well then put a Logout button in case our
admin will want to logo. First in components,
we'll create a new file and we'll call it
adminnavbr dot Jsix. We can take our current NAV
bar and paste it there. Then we will delete the car
icon, Mobile navigation, add a function for logout, that will remove the token from the local storage and also will redirect us to
the customer facing. Then instead of this
unordered list, we can put this button
there and we will add our Logout
function to OnClick. Now, we'll go back to apt JSix and we already defined the dislocation and
is admin route. And you can see we are
using this for a footer. When we are in admin route,
the footer is hidden. And we can just copy this, put it on top there, take this navigation bar and put
it instead of the footer. But in case we are
in admin route, we will use the admin
navigation bar. So internal operator on true position, we will
put this snap bar, but we will at the Adminovbr
and we will import it. And as we copy paste it, don't forget to change this
name to Admin nav bar. And then we will use
the export there. And import it into
our Ab Doja six. Now, if you'll go onto the page, we have di Logout, and
if we click on it, we will get to customer facing. And now for the admin dashboard, we are using these admin routes. And these admin routes are
wrapped in protected route, which is one of our components. In this protected route, we are having this
authenticated method, which was set to
true because we were not using it when we were
developing the project. But now we have the JSON
webtokenFunctionality, so we can delete
this return to True. And uncomment this return, that will check if the
token is in local storage. In case it is, it will return children and it will render
the Advantage board, and in case not,
it will navigate us to login page.
We did slash Admin. We will login, and we go to JSN WebTken into
our local storage. Now, we'll go back to customer facing and then back
to Advantage Board, we don't need to login again because we still have it stored.
26. Jwt Auth For Requests: We are locked in and
we'll try to call the endpoint that needs
this authorization. So let's click on Edit So file, and then we'll try it and
we will get an error. So if you will think of
it as some passport, we have the password, but
we are not showing it. We will now need to go to
pages where we are editing, creating or deleting
the product or simply to pages where we want
to authorize the request. Now, as we'll be using
this part of code, I will explain it
there on a new page, and there we'll be adding
it to our request. First, we need to
get a token from the local storage and
save it into a token. And now we will set a
conflict that we'll pass as an argument
to our request. First header will be
the authorization, and we will reuse our saved
value from the local storage. Then we will set the
content type to Jason. The setting is
Exos doing for us, so we don't even
need to set this. It can only help us to prevent
some issues in the future. Now, we will copy this and we'll go on to page where we want to
edit authorization. I will paste it there, and
now I can reuse the config. So I will go into my function, and there next to data, I will include as third
argument, the config. Now I will save it and I
will try on my page to edit the product. And it's working. Now you'll edit
also for delete and creation as a second argument there and as a third
argument there, we will delete the product, and we are also able to create it. And that will be it
for the authorization with JCN lab tokens.
27. Ui Fixes: Now let's fix the teams
and play with the UI bit. We will go into Tem Tagle
button and there we will use light and dark team
instead of the Business one. For set this dark mode, we will set dark also don't forget we need to set the data
team there in index HTML, and I will use their
default light. We will update the UI
of the Admin Dashboard. Let's go to Admin J six. First, we will remove their
background gray to 500. Then we will delete text colors, and we can change this
background to background base 100 and on Her
background base 300. And then we look like this. Now we will go to stats and there we will set text base 100, and we will put it also
for the other stats. And for a third
one, we will also add a different background. We can add the accent and
also text secondary content. That way, it will
look like this. Now we need to update
it also there on our at item button
back on Admin page. We will put there
also text base 100. Now only the logout is missing, we'll go into Admin Navbar, and there we'll
remove this text bag, and we'll set there
a DCI class button. Also, we'll remove there
a background base to 100, and if we'll go to
a second Navbar, we'll remove the background
base 100 also from there. Now, our admin dashboard
will look like this, so we can logo, and there we can just update some colors
of buttons we have there. And also, I would add some
vertical margin to sections on homepage for this div that is holding
the Welcome text, and I will add the
margin to bottom 24. Then we'll change the color for this Show button and we can change it for button accent and we will go into dark mode. We'll want to highlight
the cards a little bit. Let's go into product card single and we'll set there
background base 200. Now we'll fix it also
for login and register. So let's go to the login page, change this for background base. Go on to register and
do the same thing, and then for edit, delete or create product.
Let's do it also. So there based to 100,
we can copy this. Put it also there
on delete product. And there on edit product, from there, we will
delete the text colors. Change this two button. For the back button there we'll put instead of background
white background base 200 and we'll set the
border to base 300. So we can again copy this
base and change it to all borders Now it
will look like this. For create product, we
will do the same thing, so we'll change the borders. Delete the text color. Set their background base 100. For the Back button, I will set the button class and I miss there one
more border, so there. Also with the text color, And now for the deletion, we will change it to
background base 300. From there, we will
delete the text color. From there, we will also
delete the text color, and for the link, we will
add the bottom class. So we can actually delete
the background base we edit. It will look like this. And that's it for
the admin dashboard. Now let's check how it looks
like on a mobile phone. And we need to fix
the logout button. So let's go quickly to
Admin navigation bar. And we will remove this hidden, and we'll just leave
their display flags. And now that should be it. So
let's check the dashboard. Let's try to add item.
Let's try to edit item. And everything works. And by the way,
if you would like to show only, for example, first three items
on your homepage, you will go to Home J six, and there below the use effect, you will create the
constant latest product, and you will slice the
product you got into the state variable by the number of products you want to show. So I will use their tree there I will get
this latest product. I will input it there, save it. And now on my homepage, I will have only three
items displayed. And maybe I will get
there some more margin. So let's change this margin to top to actually
vertical margin. Now, we'll go to card and also change the background
to background base 200. One more thing we need to do in tailwind configuration JS. We'll go there, for example, above plugins and we'll
set there also dark mode. Then we'll make sure
our dark mode will stay even if we will be going
through different pages.
28. Deploy Vercel Updated: Will use versal and
deploy our website. What we need to do, even before pushing this
project to Git, we should add Git Ignore
because we need to ignore the environment
variables mainly from backend. We are storing our
secrets and passwords, and the Git Ignore is located next to front end and
Backend folder there. You will create it dot Gidgno, put there these values. But the main one is
Bendslash dot NF. Now we need to check if we have this environment variable
for Bend base URL. This one, we now need to use instead of all
local hosts 3,000. For example, on homepage, we have this dot get HDP
Local Host 3,000 product, and now we need to change
it for the value that we have there in our
environment variable, which is the Vet react app. Let's take this
name on Home J six, let's change. And
also be careful. These are backslashes, not
the normal single quotes. Now, like we did there, we'll do for all local hosts
we can find in our project. That means you will click on this search or do
Sutter o Shift F, and there you will
input local host 3,000 to find for you all the files where you
didn't change this yet. You will change all local host 3,000 to this
environment variable. You can see the
changes I did there. After we did this, we'll go into Bend folder and
create a new file. You will name this
file versal dot JSON. After you will create this file, you will insert this
because it will specify for Versal where is our index
dogs in the folder. Then we will go into
front end folder, and there we will also
create the VersL dot JSON. But there we'll insert
just rewrite source and destination to index dot HTMOEactly like I have there. In case you will be then
failing on deployment, go to package the
JSON and like I did, change Cloudinary
to this version. Before it was to
some version 2.2, and when I was deploying
it, it was failing. Then I lowered the
version and it passed. But now I will show you how I do the deployment in versal. Versal will be taking our
project from Git repository. So what we need to
do is that we will just hit a command sotorShift B. There we will hit Publish to Git there you will put the
name for your repository. I can put there, for example, products two, hit Enter, that way it will get
published to Git. In case you will do any
changes. Let's try it. Let's put there index CML, something like this and save it. You will then have your changes
there in source control. And in case you want to update the repository
and push it, you will click there on Plus. You will put there
some Commit message, update, and you will
click on Commit, and it will put these
changes also to Git where you will then
have your updated project. Now you will go to Versal
and there we will log in. I will click on a new project there I will have the
project I just pushed. So Marin digital products, I will click on Import. There I will leave
Or for directory, you will click on
Edit and backend continue and then in
environment variables, you need to set all the
environment variables you have. So we will go back to VS code. If we go to our Bend folder
and to environment variables, we will need to copy paste there all these environment
variables we have there. So let's start. First,
I will input there JWT secret and click on AD, and then I will add the
next environment variable, front end URL, and this
one be Local host. This will be the actual URL of the front end we will
deploy after this backend. So for now, we can
leave this empty, d it like this, and
we will update. But now keep adding rest of all the
variables we have there. Now you can see I edited them there and we will
click on Deploy. Now our page is deployed. You will click there
on your project, and we'll do deployment
of the front end. We'll click on Add New project. There we'll use the same
repository as we used before. We will set the preset for wet. There we will click
and edit to front end. So the root directory
will be front end. And then to
environment variables, we will check which
one we have in front end folder and it's
this one, so we will copy it. Put it there and into value, we'll put the URL
of our backend. So let's go to our
Bend deployment and then we'll copy this URL. We will paste it there.
But before the URL, we'll put HDDPS slaSAS. Otherwise, we won't be
able to do the request. Now we click on AD,
we'll hit the Deploy. Now our page got deployed, and now we need to take
this URL of the front end. Go into our Bend
application deployment, click on the project, click on settings, go into
environment variables. And there we need to input the front end URL that we got by this deployment
of front end. So we will click on Edit. We will put there the URL, and we will put there HTPS. Now we will click on Save. And after we will change this, we will go into Deployment and there redeploy and redeploy. Because as we change the
environment variable, we need to redeploy
the back end. And now on our page, we
can try to buy a product, so edit there,
proceed to checkout, and the stripe is working. We can just pay this that's it.