Hey, guys. How's it going? I'm back here with another video,
and today I'm going to be showing to you guys how to build a full stack
application using React and Firebase, where the users are going to be able
to track their expenses. Now, you've probably seen a project
similar to this in the past, and the reason
why I chose this project for this video is because it isn't that long. You can see by the length of the video, but also it teaches you
a lot of the good fundamentals that are important
with any full stack application now differently from how I usually make
my videos, I'm going to be focusing a lot on establishing good practices
while writing my code. So although there might be simpler ways
to do certain things
I'm going to be making in this video, I'm going to teach you guys how someone working in the industry
would actually build it. That means since racing react,
I'm going to be using creating a lot of custom hooks, organizing the code
in a way such that it's efficient for multiple people to collaborate in
and just make it high quality code. If you're interested
in, just check out the code. It's totally fine by me. The code will be in the description. I'm going to give you guys a demo
real quick right here. What we're building is, like I
said, an expense tracker application. The UI isn't perfect. I try to make it as cool as it can be. However, like I said many times
in the past, I'm not perfect with success. That's not what I usually do. So for me really doesn't matter. It's more about the functionality, right? So this is how the application goes. You can sign in with Google. You guys can add other ways
to sign in as well. Then you can choose your account. I'm going to choose this one over here and as you can see,
it will log into your account over here and it should keep track
of all your previous expenses. Whatever you did. You can see one thing that is there. My opinion it looks kind of weird now is just
the picture is kind of pixelated, but that isn't a problem
with the coding itself. It's just that for some reason I put a picture of those pixelated
with this Google account. What this does is it gets the profile
picture with whatever email is associated. Whenever you log in
and you can see it's all it tells us. The total balance of our tracking list,
how much income we earned, how much expenses we expensed. Right. And the list of transactions that happen. So if I, for example, went to I don't know, I just did a paint job. I'll put a paint job. And I actually did this to a friend
who offered me $200. I would come over here and do this. I would choose between income or expenses. In this case, I'm gaining $200,
so it is income. And then click on add transaction
and you see my balance increased, my income increased and this transaction
is down here at the bottom. But if I decided that for some reason I want to buy a gift for a friend, I can put over here gift, gift and then put that it cost, I don't know, $80
and then put expense. You'll see that same thing happens. Gift appears over here
and our balance should have decreased. So it also works
like there's a lot of minor details that I made sure to add to this so that we
can make this look as good as it can be. For example, if I had to pay rent
and for some reason the rent was like $2,000,
you know, the thing will become negative. So the the actual thing handles
the negative sign over here and where
the the dollar sign appears over here, all of that you'll see as we play along
and we code in our project. And by the end,
if you want to change your account, you can just click on sign out
and remember that all of this is is persistent per your page, right? It is all stored
in this case on the local storage. So you can log out, you can refresh
the page, you can change tabs. It doesn't matter.
It will keep all the data saved. So this is basically the project
we're going to be building. Before we get into the video,
you can leave a link and subscribe out. Massively appreciated. And let's get into the video. before we get into the video I would like to talk a little bit
about today sponsor Skillshare. For those who don't know, Skillshare
is an amazing online learning platform that has literally transformed
my approach to coding. As you might know,
I have great relationship with Skillshare since they have been supporting my channel
for a while now. However, this relationship started way
before my first video because, as you might know,
I am a self-taught developer and I actually used Skillshare to tune and improve some of the skills
that I was lacking through my learning journey. For example, I remember
I always had issues with access, as you might know, through my videos, but I decided to take this fantastic
course called Modern CISSP, writing Better, cleaner, more scalable
code by the author Harry Roberts. And not only did it
help me fine tune my skills, but it literally changed the way
I approached access coding as a whole. I literally can't recommend it enough. But Skillshare is not just about access
or coding. It also offers
thousands of inspiring classes on everything from illustration
to entrepreneurialism. The best part of all of this
is that you can literally access all of this for free. Yes.
You're literally heard me right. Skillshare is offering a one month
free trial for the first 1000 of you guys who decide that you want to explore and
learn from their incredible class library. So I kind of have this challenge for
you all. If you have any skills
or anything related to programing or even outside of programing, it's always
good to improve your different skills. You should go
try at least one month of Skillshare. Take control of what you're learning
and redefine what you're actually working with. Set new goals and see what you can achieve
from all of this. Again, thank you
Skillshare, for sponsoring this video. If you guys want to check it out, don't forget to check out the link
in the description. Now, let's get into the video.
Okay, everyone. So let's start writing the code for this
video differently from a lot of my videos. I'm going to literally
start everything from scratch. The only thing that I won't be focusing on
this video is the cassettes, which is standard for me because the video's purpose
is to just focus on the functionality and the technologies that we're learning
and not having to spend 30 minutes writing the thesis that maybe
you guys won't even copy them today. But I did register this as a go. So in the beginning, so as I go through the video,
I'll be pasting some says I will be writing
the class names for each element and I will be leaving
all the code in the description if you guys are interested in it. So let's start by building our project so that we were going to do
this is you can use NPM or yarn. I like to use yarn,
so I'm going to run yarn, create, react just like this. And then we'll put Dot because we're going to create everything
inside of this folder. So we're going to start out when this is done by actually
setting up our folder structure first so that you guys can have an idea
of how our project will be organized. Okay. As you can see,
we just finished our running. The command create backed up so now we can
actually start working on a project. First of all,
I do want to delete some of the files that come with the great racked up.
I always do this. I want to delete the set of tasks, report
web vitals, logo index stats. Yes. And the app to test that. Yes. I do this as always, because they're not
going to be useful for my video because we're going to be testing
this video. I have videos and testing
if you guys are interested. And this is not going
to be a real project. So it really doesn't matter. End of day and it will make the folder
structure a little bit less confusing. Most are going to clean up some stuff
like deleting the initial boilerplate that comes with the application
and some of the imports so that our app can run smoothly to test out
if everything is working. I'm going to just run yarn start
and hopefully the browser over here. It should reload to an empty white page
as you can see. So what I want is a following. I want to start out by organizing our project in a way
that it will make our project efficient to work alone and also efficient
to work with other people. Like I said, I'm going to be focusing a lot on best practices
and good practices in the long run. So I won't introduce this to you guys. So the way we're going to run
this is we're going to have two pages in our application, which means we're going to have two routes
in our application. I like to structure my pages and routes
by creating a folder called pages. in this folder, whenever I have a
page, which I'm going to have two of them, I will create a folder
for each individual page. For example, as you saw in the beginning,
we had the first page, which was a page where you can sign in with Google. So I would call that page
authentication for us. And then we also have another page,
which is where we actually have the dashboard
where you can add the transactions and do all the expensing
and all the tracking. So with that page, I'm going to call it
expense tracker, just like this. I wrote expense wrong,
so I'm just going to fix it. So I'm going to have those two pages
for now. Will leave those folders empty
because we don't want we're not going to read the files yet, but
we're just creating the structure right. Then what I also want to have
is we're going to be using Firebase for this project. And if you've ever worked
with Firebase before, you know that there is a little bit
of configuration locally. With Firebase, the configuration is extremely simple
and can be done in almost just one minute, but we do need some space to store
all of the configuration files and in the future,
if we need more configuration files, I can also put all of them
inside of the folder called config, which I always like
to have inside of my projects. Then what I want to do is finally we're going to be using
some custom hooks to work on this project. So I will create a folder called Hooks. If you've never used custom hooks
as a way to improve the efficiency and the quality of your code, don't worry, I will be showing us
exactly how they can help. Just just keep in mind
that we're going to have them and we're going to put them
inside of this folder. And now this is pretty much a folder
structure done. If you're
if you're going to put components, you can create a components folder,
you can add more stuff as you go. You can even put individual hooks inside of the individual pages
if they make sense for those pages only. But in this tutorial,
this is the structure of what we're going to be working on. Now, what we want to do
is we want to start by adding the packages that we're going
to be using in this project. And to be honest, for simplicity reasons, we're actually
just going to be using two dependencies. So the first one is going to be
and I'm going to add it by running your and I'm going to run React router done this over here
is what's going to allow us to have different pages
and different routes in our application. I believe you guys are all familiar
with this library already, so I won't be going too much in detail
about what I'm going to be doing with it, but it's one of the most popular libraries in React, so I expect
most of you to already know it. Then we're also going to add Firebase,
which as you might know, it will install everything
related to Firebase for us. But we're going to just add those right
now and start building our application by actually setting up
the initial stages of our Firebase app. So to do that, we're going to open up the
Firebase console inside of our browser. So the way I do this is you
go to Firebase Dot, Google.com and you'll see this probably you have
to probably sign in with a Google account. I already have mine and I'm going to go
to console by clicking on this button. It's going to open up your console
with a bunch of projects that you have used in the past. This is my Firebase account
that I use for my videos, so there's only stuff
related to my own personal videos, not really any projects
that I work on my own, but I'm going to click on Add Project
over here and we're going to start
setting up a new project. Now let's call this expense tracker
since it is what we're going to be building,
but you can call it whatever you want. Now it's going to ask us if we want to
set up Google Analytics for our project. Now, if this was an actual project with with like I was going to deploy it, of course I would do this
and I do recommend you're doing this. But what we're going to be doing
is just creating the project and at the end I will deploy it,
but it won't be used by anyone. I would just deploy. It just showed you guys
how to deploy this application. However, we don't need analytics. In your case, you might need it,
so I would recommend actually using it then weekly concrete project
and it will start creating our project whenever this is done.
Are we back to continue? Okay. As you can see, it is done. And we know that
because it says that it's done. So we're going to continue and we are inside of our dashboard,
which is pretty good. So the console for Firebase is really,
really intuitive. We have over here on the side,
we know that we are instead of a project
because it says expense tracker over here. But we also have
this thing called built over here. You can see all of the different services
that Firebase provide to you. So Firebase isn't just a database or
isn't just authentication or deployment. It's actually so much more. And I've made so many to Tourism
firebase in the past. You can check them out. But if this is the first time
you're working with Firebase, this is what we going to do. And this and this approach
is going to have to service is being used. You're going to have a authentication
and FIRESTORM database. Now, this is for the database. We're going to set that up later. But initially, let's just set up
our authentication and click on it and it's going to open this up.
We're going to click on Get started. Then it's going to ask what kind of authentication
we want to have. It's really easy to set up
any kind of authentication you desire. The one I like the most is Google, because everyone has a Google account
and you just have to click on your email. I'm going to click Enable
and I'm going to click on my email. Then over here
we're going to click on Save and we're going to actually start adding the authentication
provider to our project. Now, as you can see,
it says that the status for Google authentication was enabled,
which is pretty good, and means that we can actually start
using our project. However, in order to connect the project
that we have in our code, in our yes to the code and the project
that we have in our console over here, we have to click on Project Overview right over here and then there's
going to be an option over here called Web because we're setting Firebase
for a web app. And then over here it's going to ask us
to register our Firebase Web app. We're going to give a name. You have to give a good name, in my opinion,
to something that is memorable for you. I'm literally going to call it
expense Tracker just like this. And I'm going to set up Firebase hosting. The reason why I would do
this is because in the end of the video, I'm going to be deploying this app
and if you want to do such thing, you also set up Firebase hosting. Then I'm going to click on Register app and I'll have to wait a bit
until it's done. So now that it's
done, it asks us to install Firebase, which we already did. And then it asks us to copy
this piece of code. This code over here will be, like I said,
the full configuration of Firebase. Like, we're not going to have to
do anything else other than just copy this and paste it into a file
instead of a project. So to do that, I'm going to open this up,
go to config and create a file called Firebase Dash config
just like this dot. Yes. And then over here
I'm just going to paste the entire code. now that this is here,
I'm going to save this. And this should already connect everything
with our own project. Now obviously if you want to make all of this
into environment variables because you're going to post this
on GitHub, you can do so. But since I made the lead this app
right after I post this, it doesn't matter to me. You guys can see my API key
and everything related to this, so I'm not going to waste time
creating environment variables. But this pretty much configures
everything for us. However,
we do need to install the firebase yellow because this is what we're going
to be using to actually deploy our website to Firebase now it's going to ask us
to install the firebase. Yalla. Which we need to use in order to deploy
our app in hosted inside of Firebase Choosing AMPM. It's really cool. You can just run this command
in any one of your actual command lines
because we need to install this here like globally to
then use it inside of your project. So since I'm using yarn, I'm
just going to run Yarn Globe go add and then you run Firebase Tools. I already have this global installed
so it doesn't really matter to me. I'm not going to run the command, but you do have to do that if this is
the first time you're running this app, particularly next. And then I'm going to go to this options
over here. It's going to ask us
to deploy our app into Firebase. Now, the reason why it's asking to do this
first is because we can test our app already
deployed. Obviously,
we can prevent people from accessing it, but we can already start
doing this process and I'm going to start doing
just the first two, which is having a log into our very basic account inside of a project
and then initiating it. The last one I'm going to leave
for the end of the video so that we start the deployment process. So I'm going to run Firebase log in. It's going to ask us to log in. It says,
I'm already logged in with my email. Now I'm going to run Firebase in it and it's going to initiate a project
for us. We're going to choose
which Firebase Features So now there's a couple of things
that it's going to ask us to do, which is it's going to tell us to do ready
deployed to Firebase hosting. I'm going to leave all of this to the end,
but I will keep track of the commands that we actually need
to use in our project. So this is something I only know
the commands nowadays, but back in the day
what I would do is I would come over here and I would just write again
in Firebase log in and Firebase and it and then Firebase deploy. You can also just check the page again. But this is just so you don't forget. We're not going to do those now. We're going to do this later. Whenever we're done with the project
and we start deploying. So we have everything organized, but we're basically done
with the setup in our video. Now what we have to do is we have to start sending up authentication
inside of our project and to do that, we have to first create
our authentication page. so let's start setting up React Writer
Dom In our project. I'm going to zoom in a bit
so you guys can see better. We already have installed the package,
so I'm just going to import from React Router DOM and what I'm going to import is first of all, I'm going to import
a browser router and call it a router. Always do this, then import a route
and then import routes. So if you're not familiar
with directory dom, just keep in mind
that this is the standard syntax for it. Each of these components
have a different purpose and I have a lot of videos with extensive explanations
on what each one means. But basically if you want to set up
some routes, we have to first initiate the router in our project
to let react, know that we have a router. Then we have to distinguish
where in our code our routes will be defined
by using the routes component. And then instead of your,
we can define each route individually
by using the routes component. The single, the single or route component. And instead of a routes, we're just we're
just going to have to route in our app. We have to define a path
which will just beware. Like how do you set up here
you are el to go to this route. So the initial route
is always going to be an empty slash because that's the base URL for a website. And I want to switch that. When you go to the website
and you're not logged in, you're just going to automatically
be sent to the authentication page. So they'll send the syndication
page is going to be the initial route I'm going to set up
which component will be rendered when you go to this route
by using the element prop over here. And we haven't created the off page,
but we will do that right now in order to pass it over here. We're going to come to pages
and we're going to create an index dot GSX
Now this is going to be a React component. That's why I called it a GSX. And the reason why I called it index
is because the way I like to organize my folders is I already know that this is
the authentication component, right? This indication page
because of the name of the folder. So the file, I'll just call it index
to keep everything standard. Then instead of here I'm going to export a constant called us,
which will be our component. And at the end for now
I'll just return a div saying Hello world, something like this. Right. And then over here the top import from the pages folder slash off slash index. I'll import the US component
and all I have to do now is just plug this inside of here
by defining the off component as the component that is going to render
when we go to this route. now you see
we put an exact thing over here and this is just because we want to tell
basically our page that this has to match the exact route that we set up in order
to go to this route. Then we want over here
to define the second route, which is going to be the one
with the expense tracker page. So I'm going to set up a path and call it
expense tracker, and I'm
also going to put a slash over here. Then I want to set up the element,
but we have created the page, so I'm going to do exactly what I did
with the US, which is I'll come over here and I would just copy this page pasted
over here, but then change this to me. Expense tracker. Right. And I also add something over here
so we can distinguish the two pages and kind of know that this
everything is working right. So I just come over here, setup expense tracker, just like this. And now we just have to import at the top the expense tracker from Dogpatch pages
slash expense trackers slash index. Right. So we set up our routes
and we can check to see if everything is working
by coming over here. And open this up. And you see that
when we are in our basically normal routes, the initial route
we see Hello world, which is the off page. But if we go to the expense tracker,
we should see Hello world expense tracker, which is pretty nice,
which means our routes are working. Now let's start working with the pages
individually. I'm going to come over here and we're going to open
up, close this and open up the off page. Right this part over here. Now, like I said,
our off will be pretty simple because it's just going to be
a Google authentication. Now in order to set up
Google authentication, I'm going to first give this a class name. Like I said, we're going to be having some success, but
it's going to be the focus of the video. And you guys can just copy the class
and copy this just later if you're interested in doing that too. But we'll then put a P over here, a P tag, and then just write something like sign in with Google to continue. Then we're going to add a button which is going to be seen something like sign in with Google and the button. I'll give it a class name of log in with Google Button, something like this. And we actually have to set up
the function which will sign in with Google. We'll call it sign in with Google. Now, this function seems like
it would be hard, but it's actually going to be pretty simple. We're just going to create it over here
and it will actually call a part of our Firebase package, which we have to define over here
instead of our config part. So in order to set up authentication in our config, we just have
to import some stuff from Firebase. So I'm going to say import
from Firebase Slash auth because when you're going to import
something from a specific service, you just do firebase slash to service and
we're using the authentication service. Now. What we want to import
is the function get us and the Google Google auth provider. The get our function just determines
that you're going to be using authentication in this project. And the Google auth provider is obviously used for setting up
Google specific authentication. Now all we have to do is come down here
below the definition of the app and we'll create a constant
called off and set it equal to get off and then pass in the app
and then create of of variable called provider and set it equal to new Google auth provider. And we do need to access those two things
elsewhere in this project. So we're going to export both of them and we'll just come to our ask over here and import both of them
by basically just importing from and then we'll go back
once, go back twice, go to Hong config, slash firebase config and import the path and the provider just like this. Then what I want to do is I want to import some functions from Firebase in itself. So we'll import from Firebase slash off
like we were doing before. And we have a bunch of functions
that we can use now, a bunch of different
assigning functions. Like I said, you can sign in with Google or you can sign in with your email,
with your phone number however you want. And the one that I want
is the one where we sign in with a pop up. I want to pop up to appear
and you click on your email account. So we just write, sign and with pop up
just like this. And over here we'll just call this,
we'll say sign in with pop up. Now, this is going to be an asynchronous
call, so it's going to be gender promise. So we do need to make this into
an async function, and we're going to create
a variable called results, which is going to be equal to the
oh wait response of this function. Results will include everything
related to the user who just signed in. So we're going to be using this in a bit. The important part is this over here,
where in order to sign in with pop up, we do have to pass in the other variable
and the provider. So for starters, this should be working
and we should console.log the results just to kind of see what we're going to
get back whenever someone tries to log in. We'll check this out by going to the log
in page, this one over here. And we see that currently
we have over here the text and the button to sign in with Google.
But does it actually work? So let's click on this button. You'll see that some emails popped up. We have to choose
which one we want to use. Now I'm going to choose this email over here
and hopefully when it's done, log in. It should return back. As you can see information about this user. So as you can see,
it's an object called user credential. And there's a part of the object
called user, which if we click there, it actually contains
a bunch of information about the user. This is a fake email account you have, which includes a display name for the user, an email information
like a profile picture and much more. But we're only going to be using
those three things so we can see that we actually have the information
coming back and we're actually logging in. So what do we want to do with this
information? Well, what I want is I want to keep track
of a couple of things. I want to keep track of the user ID,
the name of the user, the profile picture,
and if the user is logged in or not, because those are
the things that we need in our app. So what we want to do
is we want to actually store a bunch of information
inside of our local storage. The reason why we want to do that
is because if you go over here and go to local storage, it's on the application
tab and you go over here, there's nothing right here. But what this does is whenever a user log
in the first time, they log in and they see we saved the information
to the local storage, they can close the tab,
they can refresh the tab, they can switch tabs,
they can leave the computer and come back. And that information will be kept there, meaning
that they don't have to sign in again. So we do persistently
keep the user logged in. Now, it's not the safest way to do it. I would actually recommend using cookies, but to make things simple, I'm
going to store it in the local storage. They're not that different to
to handle with So we can do this by just coming over here
inside of our code and actually just saying that we want to set an item
to the local storage. Now, what item do we need to set? Well, I want to set an item code off,
and I want this to be an object full of information
regarding the user. Now, if you've known or worked with local storage before,
you know that you can't store objects. You can only store booleans,
strings and numbers, I believe. So what we want to do is
we want to turn the object into a string and then turn it back
whenever we need it as an object again. So this is a very common way to do this. We're going to actually create the object over here
that we want to keep for the user. So we're going to call this off in full and set it equal to an object. And then the object. What we want from it is
we actually want an object that has a user ID
which is going to be equal to the result from our users. Any in user recall we had a user object that you ID, this is the ID that we get. How do I know that this is the path to it? Well, if you go to the console,
you remember we have the object, we go user and then we go dot you
ID and we're going to do the same thing for the display name
and the photo yourself. So we'll just come over here, set up
the name to be equal to result, dot user, dot display name, and then the profile photo to be results. Dot user dot I think is is a profile photo is photo yourself
just like this? I also want to know if the user's logged
in or not because this is important. So say is off is equal to true
because we're logging in, right? And then we have this object. What I want is I want to set the local
storage item to be equal to this object. Right. But as I just said, you can't do this because you can store
an object inside of a local storage. So what we need to do
is we need to use a function from JSON called JSON, not string ify. And this function
turns any objects into a string which can
then be stored into the local storage. So this should pretty much be good. We're going to test to see if this is
working by trying to log in again, by clicking
this and then clicking on the email. We want to log in, we're going to
check out to see if it's console logged. It wasn't
because we removed the console log because now we're actually just storing it
in the local storage and you'll see that it is over here. We have, as you can see, an off key
instead of our local storage with a value of a string
that kind of looks like a JSON object, but it's actually a string in the format over
JSON object with the JSON package over here, we will actually be able
to turn that back into an object later on. But this means that everything
seems to be working. What we want to do after this is right
after you log in. We don't want to keep the user
inside of the sign in page. We actually want to navigate them towards the expense tracker page
because they just logged in. So in order to redirect you
to another page, we're going to be using something from React
very dump called the navigate function. So we're going to go to import
from React Rotterdam and we're going to import a hook called
the use navigate hook just like this. Now, up here at the top, we're going
to define a variable called navigate and set it equal to the use navigate hook. I'm actually going to call this a constant just for standardizing purposes,
but basically this function, whenever we call it just doing this,
we can actually put over here a route to which we want to navigate towards,
and it will take the user there. So I'm going to put that
we want to go to the expense tracker page and you'll see that whenever I log in
and I'll try logging in again, Now we just choose the email
we want to log in with and you'll see that we're now redirected to the expense
tracker page, which is perfectly,
exactly what we want it. Now it's time to start
working on the expense tracker page. So we're going to go back to the index
digest file that we created for it. Currently, we don't have anything, but we're pretty much done
with the authentication page. We just have this text saying Hello world expense Tracker, but
we want to add a lot more to this page. what we want to do is we want to set up this structure
for how this page is going to look like. I'm going to delete this
and I want to add over here this and we're going to call it I'm going to add a class name and we're going to call it
expense tracker, just like this. Then I want to come over here
and add another div and call it container. Then just delete this and add a name
with a class name of container. Now instead of here
we're going to add an H1 tag that is going to say expense tracker. We're later
going to add the user's name over here, but for now we'll just keep it like this
and we're then going to add a div which is going to display the balance, the total balance for user's expenses together with the user's total income
and the user's total expense. So we're going to add class name to this and call it balance
because it's the balance part of our app. And then I want to add an H three tag. Seeing your balance. Then down here,
we're going to add some sort of number For now, it's going to be an education
du tag to do this, but for now
we'll just see that the balance is 0.00. Right? But we're going to add
the actual dynamic balance in here and then going to add another div together with the summary of both the income
and the expenses. We're going to give it a class
name of summary and we're going to add another div with for the income and a div for the expenses. Right? So I'm going to call this income and I'm going to call this expenses. Okay, So expenses and for the income,
I'm going to add an H4 tag because it's even smaller
and it's going to be called income and I'm going to add a P tag
to display the income. So a paragraph tag, which for now again similar to the balance,
I would just put 0.00. I'll copy this and paste it over here
and just change this to expenses. And we should see that it's starting
to kind of look like what we want. But obviously all this SS hasn't been added yet and a lot more
should be added to this website. So now that we pretty much set up
the top part of this page, we're going to start creating the form that is going to be
used to add a transaction. So I'm going to create an actual form. I'm going to call this form add transaction. And then over here we're just going to add an input which will be of obviously type text and then I'll put a placeholder for it
so that you just can know what you're going to type here and it's going to be the description
of the transaction. So like the name. So like if you added a haircut, it's going to be haircut,
you know, something like that. We're going to make it required because you do have to do this
in order to finish the form. And for now we'll just keep it like this. We're going to copy and paste it again
because we need two of them. The second one is going to be
for the amount of of of the price, right. Of the expense or the income,
whatever you choose to use. It's not going to be
if type text is going to be a type number because
because this is going to be a number. It's also going to be required. So it's pretty much set like this. Then we need to add the radio buttons
in order to determine
whether it's an expense or an income. Right. So we're going to add
an input of type radio. And since this is a radio button,
it's a bit different. We're going to add an ID over here of expense and a value of expense. So this is going to be the expense one
and for now we'll just remove this and also not add anything else. But we're going to add more stuff
for both for all the inputs, to be honest, because we're going to have to make them dynamic
and save the information in each of them. Then for the radio button for income, we're just going to change this to income
and this to income as well. Now for each of this radio buttons,
which you need to need, we you need a label to them. So I'm going to add a label
to say exactly what they are. The first one is for expenses
and the second one is for income just like this. And we
have to attribute each of the labels by using the HTML for property. So this is for the expense one. So we just copy the idea of this one
and put it over here. And this is for the income one. So we just copy the idea of the income one
and put it over here. So now we have our form pretty much done. All we need is a button
to submit the form, so we're going to put a button
and give a type of submit so that whenever we submit this form,
it knows that it will be submitted. Whenever you click on this button
and we're going to write a text, same ad trend. This is action just like this. Let's check to see how it looks. And it looks kind of cool,
but it's obviously not the format and structure
that we'll look at the end, but it looks like we pretty much
set up the skeleton of this. Now we also want to have the transactions
part of it, which is going to be
a list of transactions. And the wish structure in my UI made is such that I'm actually going
to put the transactions part outside of this major expense tracker over here. We're going to create a separate
div called transactions. And the reason why I added this fragments,
if you don't know, is because whenever you have your returning,
you need to return only one thing, right? So you can't return a Dave
with the expense tracker. And then another div being it's sibling. You have to just return a fragment
with two sibling diffs. Right. And then over here at the bottom,
we're just going to give this a class name of transactions just like this. And for now
we're just going to add an H3 set tags, same transactions. Just to keep in mind
that we do have to add this later on. Now, I pretty much want to start
adding the functionality to be able to add the transactions. Now, the reason why I want to add the transactions before I'm
able to see the transactions is because how am I going to see a transaction
if I haven't added one yet? Right. So that we were going to do
this is we're going to start setting up our database
inside of Firebase. So to do that, it's pretty simple. We're just going to open up the building over here
and go to the far stored database service. Then it's going to open this up
a Similar to the authentication. We're going to click on this button,
which is the Create database button. Then it's going to ask us if we want to start this and prediction mode or in test mode since we are actually working
and we're going to be deploying this, I'm actually going to choose
production mode, but there's only one minor change that I need to do in order
to get things running on production, which is to add this over here
in the rules part of the database, if you're not familiar, I'll explain in a bit, but basically
I'm going to choose next over here. Then it's going to ask us
to choose the first for a location. Well,
Firebase has a lot of locations, right? That's what makes it very reliable. And to be honest, I live next to the U.S. I live in Canada. So this is the closest part to me. So I'm going to use this one. Make sure you choose one that makes sense to you and your users
because you can change it later. So I'm going to click on Enable and it's going to start
creating our Firestorm database. Okay so I've finished grading everything. And as you can see,
this is what we can see. This is basically the
dashboard for your database. And Firebase kind of uses a no sequel approach to data. So it's not like you're using my squirrel
or or Postgres or anything like that. It's a bit different. We have collections and documents. A collection would be almost like a table
in a school database, and in our case
we're just going to have one collection. The collection is actually going
to be called transactions, right? Because we're going to keep track
of all the transactions that happen. I'm going to click next and it's going
to ask us to create our first transaction. To be honest, I'm just going to click Out
of Idea over here and created. You do have to create a first one,
but we're not we're not going to use it. The transaction that we're going to
have is actually a different one. So I'm just going to delete this document
over here. Documents would be like an entry
or a row in and SQL database. If you're not familiar with this. Now, we pretty much
created the structure of our collection in order to get it working. We do have to change the rules, remember,
because this is working in production now, what are the rules in a fire
fighter store? Data? This well fire store actually allows
something really cool, which is for you to determine who is able to make changes
inside of your database so you can allow them to be able to read,
write, update, delete. You can allow them specify exactly what kind of interactions you want
the users to have with your database. As of right now,
it is said by default to only allow users to read and write the database if false,
which means that it will never allow any user to read or write in the database
because false is never true. So it's almost like a coding language
over here just for for the rules section of the first
our database. For now,
we want to allow every single user to be able to make a change
because this website is pretty simple and I don't need to actually specify
anything. To be honest, I do whenever it's
an important project, but for this we're just going to set it to true
so that everyone can do whatever they want and add in and read the database. That doesn't mean
that they have access to your database. That just means that
if they go into your project and they try to add a transaction,
they will have writing rights to be able to do that and reading rights
to see the transactions. So this is pretty much resolved. We'll come back to our data
and we have to think about what kind of data do
we want in our collection. Right? So we already have a collection. I believed we had actually did. We did a change. Maybe it got deleted for some reason. So we'll create the collection again,
I'll call it transactions and we'll do the exact same thing
we just did before. Okay, it's been created
and we'll just delete this document. So basically
we already created our transactions. But what do we want each document to have? Well, I kind of want to keep track
of the following. I want to keep track of the user
who made the transaction. So the user idea of the user
I want keep track of the description of the transaction, the transaction
amount, also the transaction type. So if it's whether it's income
or an expense and also when was this transaction created so that when we display
the list of transactions we displayed an order by the date
it was created, right? So we want to keep track of all of that. And to do that, it's pretty easy. We want to just create a function
that is going to add a new document to this collection. Now, how are we going to do that? Well, I'm actually going to create
what is known as a custom hook to handle all of the adding transactions
functionality in our project. So for those who don't know, a custom
hook is just react. Function is not a component
because it's not returning gsx it's actually going to return data,
but this function is going to use it has access to all of the,
all the hooks that come with React, which is pretty nice
because it will return data and it's almost like a helper function, but
it also has access to React tools, right? So in this case
we want to call this use ADD transaction. Now, if you're not familiar to custom
hooks, just know that every hook has to start with the name use. So this is why it's called like this
and it's standard. Whenever you want to add the functionality
to add things into your project, you call it
something like this use add transaction. Then over here we're going to create a function called Use ADD transaction. And for now it won't return anything. It would just return an empty object just like this. Right? But inside of this hook,
what we want to do is we want to create a function called add transaction, and it's going to deal with Firebase. So it has to be an async await function. And at the end over here,
we're just going to return this function. Now inside of you, what we want to use is this function from Firebase
called Add Duck. So I'm going to import from Firebase slash
Firestorm and I want to import the function add duck and add duck. As you might know, by
the name means add document and we need to wait and duck. Whatever data we put in here will determine what what kind of document
we're adding to our collection. Now, the first thing we need over here
is what is known as the specification or a reference to which collection
we want to add a document to. So you see over here we only have
one collection called transactions, but we might have many of them. So in our code we have to specify which collection
we're trying to add a document to. And in order to do that, we're actually
going to import the collection function over here. Now we have to make a reference to that collection by calling it transaction collection. Ref Right. It's a reference
to the transaction collection and we're going to send it
equal to collection. Now the first thing we have to put over
here is actually something we haven't created yet. We have to go to our config file
over here and import at the top from Firebase slash Firestorm, something called Get Firestorm. Now Get Faster will allow us
to create this variable similar to the other variable,
but instead called d b, which means it's a reference
to our database inside of our code. So we're going to say DB
is equal to get faster and we're going to pass in the app
over here. Now over here
we need to import that DB variable by saying import from config slash firebase config and then DB. Now I'm going to press enter
and we're just going to put the B inside of this thing. Then in order to actually reference
the correct collection, we have to put the name of the collection
over here. If you recall, we call the transactions
as you can see. So this is what we add over here. Now we do have a reference
to that collection. We just put it inside of the add function,
right? We just copy this and put it over here. Then what we have to put over here is the data or the object
we want to add to this document. So like I said, we want the following. We want a user ID to be something, right? We want to also pass in the description of the transaction. We want to add the transaction amount. So I'm going to put a mount over here,
which will be a number. And we also want to add the transaction type, which is going to be a string. And finally we're going to add
a property called Created at which it's going to be some sort of like timestamp
given by Firebase. Actually, all of this over here,
we'll have to get it somewhere. But the created at this firebase already
allows this. It gives a function
that will give us this information. this function we can actually just imported from faster
over here it's called server timestamp. Well, this function does
is it literally whenever you you call this function
it will give you a timestamp of the current moment
where the function was called. So if I put it over here, we'll know
exactly when this was created at and it will make sense
based on Firebase Time standards. So now all we need is this information. Well, let's think about this through. This is called add transaction. And where I'm actually going to call
this is in the expense tracker component. I'm going to come over here at the top. I'm going to import
the hook like this import from a dot slash, then go back and then go to hooks
and then go to use that transaction. And I'm going to import the use
transaction hook. Then over here
I'm going to create a consent so that you could use add transaction
and we're just going to get back the ADD transaction function. Now, what we want is to call this function
whenever this form is submitted. So we have all of the data
that the user is trying to use to add the transaction,
such as what kind of transaction it is. So the transaction time, also the description and the amount,
all of that we're going to have inside of this component, meaning that if we really want
to have access to that data over here, we can technically just pass
in as arguments to this add transaction function, meaning
that over here we can accept an object containing the description
that we want to add to the transaction, the transaction amount,
and also the transaction type. So this fields over here
that we still have left, we can just get it directly from the arguments
and the parameters of this function so we can just delete this and it will be passed down from whatever
whenever we call this function. Now the last one we need
is the user ID now to get the user ID, we have to get it from our local storage. Right? Because if you recall, when we sign in,
we set it over here. But since it's a lot of work to constantly whenever I want my
my user ID to just get the item from the local storage
and then convert it into an object. Because if you recall, it's a string
right now in the local storage as we have to do that,
I don't want to do this every single time. I want to use the user ID, I want to have a compact way
to always have the information done. So I'm going to create another hook
called Use Get user info. And what this is going to do
is it's going to actually, whenever you call this, is going to return
back to an object containing all of the user
info inside of the local storage. But in as an object,
not an actual string of fight object So I'm going to come over here,
say export const use, get user info, which is going to be a not a function. Of course. And this book is actually going
to be pretty simple. We're going to go over here and basically
said this equal to Jason Pass. And what Jason the force does
is it basically transforms string ified object in like we used the JSON string
if I before and to back into an object. Right? So it's basically the other way around from what
we did to put this into the local storage. So what I put inside of here is local
storage dot get item and we put in the off key over here because this is why
we called when we have this item. So we're just passing this JSON
and it will come back as an object, but we will destructor
the object with information that we want. So we know that in the local storage
restored a name, a profile photo, a user ID, and also is off verbal. Over here at the bottom. We want to return this separately. Now, the reason why I want to return
this symbol is because
sometimes I just need the profile photo. Sometimes I just need the user ID. We want to have this quick and easy
so that when you call this hook, you only get the specific thing
that you want, right? So right now this is pretty much done. That means that in the user transaction,
if I want to have access to the user ID that was in the local storage,
all I have to do is just import this hook. So import use from that slash use
get user info, import the hook and then just say const equal to use, get user info and just get the user ID from this. And then just put this over here. Right? Just like this, it will automatically use
this if I just delete that. So you see we basically condensed
and abstracted all of this logic into a simple hook that we can just call
and get the info back. Now, we already did to cause some hooks
so far in this project, right? And you might be asking yourself
maybe what is the point of this? Couldn't
we have just created add transactions function inside of this component
over here and handled all the logic? Why are we doing all this extra work
of putting it in another file and making it into a custom hook? Well,
because to be honest, in the real world, when you want to create your components,
you want to separate the logic from the UI. I think about this component,
the expense tracker one as mostly for UI as you can see. Right. The logic should exist separately
so that when you test your components, you can test the UI of this component and separately you can test
the logic of this hook, right? There's separate things. So this is why people usually like to add
custom hooks. It also makes this whole logic
very reusable because if I had created
the ADD transactions function over here I needed to add a transaction
in another component, it would probably have to do something
like add this into context or maybe like pass this as props. Something crazy like that. But to be honest, all we need to do
now is just call this hook and it should all be good. So we basically finished
the use add transactions hook, but we don't know if it's working yet. The only way to know if it's working
is by trying to call it over here by default. I want to just try calling it once. I'm going to create a function called on Submit, which will be called
whenever the form is submitted and I'm going to call it
make it an async function like always,
because it's going to call something. Then I'm going to basically
paste it inside this form and give this an on submit. As you can see now, since this is a form,
if we submitted, it will automatically try to refresh the page
and add something that we don't want. So we always just prevent default like this right? Then I want to call the add transaction
function right after this, because when we submit to form,
we want to submit the transaction. Right now, I'm not currently getting the data from the inputs yet. We're going to do this in a second. But before we get that, I want to test out
to see if the transaction function is working,
but just feeding this some fake data. So the first big data I want to add
is for the description. Let's pretend
that we're adding a haircut, right? So just force feed some data over here. Let's see the transaction is 22. and let's say that
the transaction type is equal to expense. Now, if I click on this button, hopefully we should see a new document
in the transactions collection. But it seems like
it deleted the collection, which happens whenever you create the collection
too early and you spend a lot of time not adding
anything to it and with no data in it. So basically Firebase just it. But that's not a problem, which is
critical action for the third time. We're going to call it transactions and
do the exact same thing we've done before. Fake a piece of data, save it,
and then just delete this. And what I want to do is we see there's
no no data in here, right? The transactions thing is still alive,
as you can see, but there's no data. So we're going to come over
here, click on Add transaction. I'm even going to open up the console
just to see, just to see if there's any errors
that appear. We click on transaction and it's asking me to fill this up,
even though it's not going to use the data from this. But it's fine. I mean, if we're going to add transaction
and let's see if the data is here, it seems like something was added,
a document was added. If I click on it,
it seems like it was correctly added. We have the haircut as a description,
the amount as the number, the expense as a transaction type, and my user ID
and also the date of when I created this. So the use transaction hook is or the use add transaction
hook is working perfectly. Now we just have to get this data from the form instead of brute
forcing it like this. Now to add the data to the form,
I'm actually going to I already created the states
and I'm just going to explain to you guys so this are
the states we're going to be using. So we're going to be using one
for each input in the form. And we only have three of them, right? We have to get the data for
the description, the data for the amount and the data for which of the two
radio buttons we clicked. So the way we're going to do this is we're
going to create three different states. One is going to be called description, one
is going to be called transaction amount and one is going to be called transaction
type. Transaction
type will be set to expense by default. I chose that
because I think it makes sense, but you can change it to income,
obviously, and all the other ones
have just their initial values. So what we want is
whenever there's a change in the description input, for example,
so I'm going to put on change, I'm going to grab the event
that is happening and then then I'm
just going to set description as the event or targeted value. I'm pretty sure you guys are familiar
with this approach of of like kind of keeping track of values
and inputs. This is the most standard approach. So this is how I'm going to be
following this. I'm going to do the exact same thing for the amount, but instead of set
description, we'll call it set the transaction amount,
which is the other state we created. And finally,
we're going to do the same thing for both radio inputs. Now it's a bit different for them
because they have the same function. So set transaction
type and set transaction type. Now when we say event or target of value, this is going to refer to
whatever value we put we put over here. And that's why I actually set a value,
because now when you click on this radio
button is going to set the transaction type to expense and over here
it's going to set it to income. Now the only other thing
we really need to do in this form is the fact that whenever I would say new status and I define let me just fix this real quick
before continue, I'm just going to import You want to import at the top over here, import from React. We want to import the use state hook
just like this. And you see it seems to be working. But what I wanted to say is even though we are keeping track of whether the expense
or the income are being selected, you see we can first of all, select both of them at the same time,
which doesn't make sense. And also there's none of them selected
by default, which doesn't make sense because I did set expense
as the default value of the state. So what we want to do
is we want to come over here and to
both the expense and the income radio. We want to add it checked property now. Well, this is going to refer to is
if the transaction type is equal to in this case expense,
then this input will be checked. If not, then you won't. Same thing with this one. But the difference is income. The difference that this makes is by
default the transaction type is expense. So it checks expense. But then if we switch to income, it's
not expense anymore. So you can select both of them
at the same time. Some basic form
handling for radio buttons. But it's really cool that it works
as simple as it does. Now we're pretty much done with our one. The reason for that
is because we are indeed keeping track
of the necessary information. So instead of brute force in the data, we can just passing the, the description,
the transaction amount and the transaction type just like this,
and we just save it. Now let's test to see if it's working. We only have one document in our
collection, as you can see. So we're going to add let's pretend like pretend I bought a keyboard with the amount of $35. It's an expense. I'm going to click add over here. It seems to have added and it seems to have kept track
of the correct information. Let's try adding an income
to see if it works as well. Let's say I sold a monitor, right? I'm going to put a monitor sold e b I don't know. Let's pretend I sold it on eBay and I sold it for $130 out in income. I'll could add transaction. And we should see that
the new transaction is a monitor sold and it is of transaction type income,
which is pretty good. So our whole functionality of adding stuff
seems to be working. This is not the hardest part yet.
I'm sorry. So the hardest part is now, which is
getting this data in the correct format. So this is going to require
a good amount of logic, but to be honest, it is not a complicated once you're done with it,
you'll notice that everything makes sense and it's a good practice
for whenever you're working with stuff like this in general, right? So since it is a lot of logic
similar to the use at transaction, we're going to create a custom hook
for getting the transactions. So I'm going to come over here, call
this use, get transactions just like this. And over here we're going to export const use gets transactions and inside of this hook we're just going to first of all, try to understand
what we're going to return, right? We're going to first
return the actual transactions. So it will be list of the transactions
that are in the database and that were made
by the user currently logged in. So we will have to create some sort of
state to keep track of this transactions so we can already create that
by coming over here and first importing. They use state hook from React, say from React use state. And I want to create the transactions state and the set trends actions function, right? This is going to be a list. So by default it will have empty array. Now what I want to do is I want to create
a function called get transactions. Now, the reason why I want to create
this function is not that we're going to send this function as a return. We're not going to return this function, and no one is going to have access
to this function. This function will actually actually
only exist inside of this hook. The reason for this is because
what I want to happen is whenever you load the expense tracker, it's
going to be constantly listening for new transactions at all times
referring to the current user. So you'll never have to call the
transactions because it will be happening consistently depending on
if new transactions have been added. So what I want to do here is actually want
to call the use of fact hook and put the transactions inside of here just like this. Now, you might ask, Oh,
why did I create an external function called get transactions
instead of just putting the logic that I'm going to write inside of here
instead of the use effect? Well,
because get transactions have to be a sync because we're going to be dealing
with Firebase inside of here and we can't have any async function
inside of a use effect, meaning that we can't just do this right
and then use the await inside of here. We have to create an external function
and then just call it inside of the use effect. And also because it will abstract
the logic inside of here without having to put a bunch
of random stuff inside of the use effect. Now for the transactions, it's actually
kind of cool what we're going to do. We're going to do
what is known as a query inside of our database. Now it's going to be a bit different
from a query, let's say on a my SQL database,
because this is no SQL, right? But regardless, it's not that hard
once you get used to it, I'll let you guys know that. So the first thing we want to do is we actually want to turn this into a try. Catch. Now, the reason why I want to turn this
into a try catch is because I want to be handling any errors
that might occur inside of this, inside of this function. Right. And in case there is any errors,
I'll just console the error or the error message just like this. And instead of the try, I'm going to put all of the things
that I want to attempt to do. And if any of them fail,
it will be caught inside of this catch and it will just error them out
so it won't break our code. So instead of the strike catch,
the first thing I want to add is I want to make the query and I'm
going to call this query transactions and I'm going to set this equal
to something called query, which will automatically import
from Firebase slash VAR Store. then, instead of you actually want to make a reference
to which collection we want to query. So we're going to have to probably create
something similar to what we did over here
called transaction collection. Ref I'm going to put this below here, and for that we also have to import
collection from Firebase and the B from our config file, right? So I'm going to import a go back twice and go to config and then firebase config
and then import the DB variable. I also want to put both of this below
the React import because I always like to have the React import at the top
and obviously I forgot to put from over here and it should be working now. So we made a reference to our collection
and we're just going to put it over here. Then what else do we need? Well, we have to specify what query
we want to make. So when you're making queries in fire
story, there's actually functions you can use
in order to make the query work. So for example,
what do we want to query here? Well, I want to query all the,
the documents in this collection where the user I.D field in each document is equal to the user ID of the user
that is currently logged in. So I have to say something like this. Well, I want to query from this collection
where and where is an actual function that you can import from fire store
where the field user ID is? And then we put over here
the the actual operation we want to make on this where and you can
see there's a lot of operations you can use in Firebase,
but the one we want is the equal sign because we want to see that
the user ID is equal to the user ID of the user. Now, we don't have access
to this variable yet. We have to imported
from the hook that we created and look how simple it will be
because we already created that hook. All we have to do is just import from dot slash use, get it user info import
they use get easier for hook and then just straight up const equal use,
get user info and just get the user ID with no need
to get any of that other information. Then we'll just pass it over here. Finally,
we also want to order the transactions and this is more a personal reason,
but we created the created add property and we add it to each of the documents
so we can just say that we want to order this by
and then specify that created add field, right this one over here, and it will return
all the transactions ordered by that. So I'll save this. Now that we have our query transactions
variable, I want to do something called on snapshot. So on snapshot is a function
that comes from Firebase, as you can see, and it will basically keep tracking
for a query if there is changes. So we'll passing this query over here and we'll then have a callback
function called snapshot with a snapshot argument. Sorry. And it and whatever you put over here
is whatever data you get back
from the current snapshot of this query. So inside of this, it contains the data that we need for the users. So it's going to be a list, right? Because we're acquiring documents,
multiple documents. So we'll probably have to loop through this list. So I'm going to say snapshot for each. And if you're not familiar
with for each, it's basically going to loop
through each element in an array, in this case, the snapshot of re
and give you back a callback function
containing each specific element. And each specific element
will be the document that you need. So order
to get the data from this document, we can actually separate it
like this, create a verbal call data and set it equal to doc dot data
just like this. The function that Oh, I'm sorry,
I should have put an equal sign. It's actually a function
that will return back. Exactly. This over here. But also I also want to have an D for each specific document. So for each specific transaction,
I want have an ID and Firebase already gives us an ID. If we say doctor ID, it will give us
a unique ID for each individual document. So I'm going to do that
like this cast ID equal to duck ID and it's not a function,
so it's just a variable. I can just do it like this. Then what I want to do is
I want to have some sort of of array called docs,
which is going to keep track of each of the documents
that we want inside of this. On snapshot function. Now, the reason why we're doing this
this way is and not just straight up saying something like set
transactions equal to a snapshot since this is already the array of documents
is because it's not in the format we want. What we want is an array containing
an object that is going to contain all of this information together
with the ID and much more. But we don't have that right now. Snapshot gives us a lot of data
and we want to condense that data. That's why we're looping through each of
the elements in the array and separating all of that information
for each of the documents and adding them to the stock. Sorry. Now we can just say docs don't push
and we're going to push in an object containing the data. Right? That is already an object
that is going to contain all of this. But also we want to add the ID
for the collection. It's not containing
data, it's contained in this ID variable. So we're also going to add the ID
inside of this object. And now we should have the correct data
filter, right? So that means that after
this snapshot is done right, we can actually come over here and just set transactions equal to docs because DOCS will now have the correct data that we want
and we can just set it like this. So this is pretty much done. The only difference is
we need to actually clean up this function after we're done, clean up the
the use effect. So I'm going to let this be equal. To unsubscribe and set it equal to
I wrote this completely wrong and send it equal to on Snapchat. If you're not familiar with this,
this really doesn't matter. Just to return over here to the bottom,
the cleanup function, which we'll just call the unsubscribe
function. Now, this doesn't really matter if you're
not familiar with what I'm doing, but oh, wait. Oh, because I'm defining this,
I need to define this above the catch. So I'll say, let unsubscribe. And this should be working. So now at the bottom,
we're returning transactions. This hook is not done.
Trust me, it's not done. But it already has a lot
of its initial functionality finished. So I do want to test it out
to see if it's working. I'll come to our index charges and
I'll import the hook over here at the top. I'll say use get transactions
and use get transactions. Then I would just contact transactions over here. Oh, actually changes to use,
get transactions and then just get the transactions
directly and with this, what I can do is I can come over here at the bottom, right
over here and below the transactions. I want to add a list,
an unordered list for each transaction. So for each transaction
I'm going to loop, right? I'm going to say transactions dot snap. So we're going to loop through the list and we're going to grab
an individual transaction Then we're going to return back
for each transaction list, write a list item
which is going to contain, first of all, an H four tag,
which is going to just display
the description of the transaction. So we can grab this by saying either
transaction description because transaction
will contain the description, but also since we're going to be using a lot of the individual items
of transaction multiple times, I actually want to
before returning this, I want to structure the transaction by saying const transaction
and getting the description, the transaction amount and the transaction type,
which are the three things that I actually want to display
for each individual transaction. Then instead of saying transaction description,
I can just use the variable directly. Then what I want to do is
I want to display both the transaction amount
and also the transaction type. My first coming over here
and adding the money sign, as you can see, and then saying transaction amount. And then I want to add
this little dot over here and just add a label which is going to contain the transaction type, as you can see. Now let's check
to see if this is actually working. It should, but it seems to not be working. Let's
check out what is happening. It says that, oh yeah, the query here requires
creating an index. I completely forgot about this, but yeah,
this is something you do have to do. To be honest, I only remembered that
I have to create an index when working with queries in firebase
whenever I get this console.log because it doesn't matter to give,
they automatically do it for you. An index it doesn't really matter for
you don't have to understand it fully. Just know that you have to create one
and you create one by clicking on this button
and they will automatically do it for you When you sign in with your account
associated with your Firebase project
So I will sign in with the email account. It will open this up. It will ask or update indexes
and it will automatically put all of the things
you need to create this index. You'll click save and it will build. You do have to wait for the status
to be completed in order to make this work,
but it should go pretty quick. Okay. So as you can see, it now
says status enabled, which means that if I refresh this, the
the transactions should appear here. So I refresh this and they do. Right. As you can see, all of the transactions
appear over here. Obviously, they look really ugly, but
to be honest, it doesn't really matter. This is how it looks so far
and the code seems to be working. One thing I do want to do, though, it is kind of styling,
but it's it's not c assessed directly. I'm actually doing it over here is I actually want to add a caller to this label. So so that the color of the text is dependent
on the transaction time. Now, the caller I wanted to be. Well, if transaction type is equal to expense. Well, I want the caller I want the caller to be read. And if not, if it's anything else
such as income, I want it to be green. So let's try this out. You'll see that now it does
change the color depending on the transaction type. Now, this is pretty much done, right? Kind of. But we do need to put information
related to the user inside of here. Now, what I want to do is I'm going to add
a bunch of the cases that like I've done personally. And the reason why
I want to do this is because for the rest of the video, one,
I want the website to kind of look cool, so I'll just copy and paste the cases
that I already have done and just kind of glance over it
so you guys can take a look. But again, I'm not going to go step by step
and build it because it would waste too much time in the video. But basically how right here says
here is for each individual page instead of the folders. I would create a styles
that says file right? And this is obviously the case in which you're working with peers
to assess if I was using something else like sets or if I was using Tailwind to assess
everything, would be completely different. But in this case
I would do something like this. I'm creating individual
styles that says file for each individual page or each thing
that I want to have styles for. And then I would just put
the individual styles over here. And then on the respective pages such as this one over here,
this is the expense tracker. I would just import
dogs styles starts to assess and I would do the same thing
for the other one over here. So I'll be back in the second win
of the season as has been pasted. Okay. As you can see, I pasted all this here
says this is the case for the log in the authentication page. It's pretty simple. Nothing major. Then this one is for the expense tracker. And just to make everything
kind of look smoothly, you can see that this is how the website
kind of looks right now. If I were to go to the off page,
this is kind of how it looks. I just noticed I forgot to add one thing,
which is there's kind of like a border
by default in React types. So what I usually like to do
is I usually like to come to the app that says and just add body padding is equal to zero and margin is equal to zero. That that should fix it up. But as you can see, we can come over here,
sign in with Google, choose the option, So I'll just choose this option
over here and again. And you can see we have our expenses. But one thing we don't have is it doesn't
see the user's username over here, right? And it doesn't show the profile picture. So I'm going to add that right now. So in order to get that information,
we already have a hook for it, right? We've been playing around with this
for a while. It's called Use Get user info. Right. So I'll come to the expense tracker one and I'm going to import
that actually at the top, so I'll just copy this piece over here,
change this to use, get user info and change this to use, get user info
and then over here I can literally just structure
whatever I need. In previous examples, we to structure
the user ID from this hook, but in this case for need
that we only need to display any or the name the profile photo. And do we need anything else? No, we don't need the is off right. We just need those two things. So for the name, what I want to do
is over here it says expense tracker. I want to kind of customize it
by putting the name over here and then putting an apostrophe s. So it's going to be like Pedro Machado's,
which is my name. Expense tracker. Oh, in this case, yeah. This is a fake email account. I mean, it says Moseby. though. So
get the reference. We'll understand this. But yeah, like it seems to be working. We've put the name over here, but then for the profile
picture is a little bit harder. It's not that it's harder, It's
just that we haven't set up like, the proper thing for it. Yeah. So where are we going to set
this up is above, below the form, below this dev,
but not inside of transactions. We're actually going to see that
if there is a profile photo, then because remember,
we're getting this information from the Gmail account and maybe you don't have
a profile picture in your Gmail account. So we all we we can't guarantee. So I'm going to put over here. If you haven't a profile picture, then I'm going to give a class
name of profile. It's good that if based on the success,
because now I just have to give the correct class names
and the styling will automatically go. So the image will be like this. I give a class name for this image
and call it profile photo, and then all I need to do is
the source will be whatever we got back from Google. So I'll put proof photo and I'll save this. You'll see that the profile photo
should appear over here. But I also want to add on top of that
some sort of functionality or some sort of button
that we can click to actually sign up. That's something that I don't know if
you guys noticed, but we haven't done yet. I want to be able to sign out in case it's
necessary. So we're going to come over here
and add a button for signing out. We'll just write the sign out
and we'll put a class name over here as sign out button and then I'll put an on click and we'll create a function
called sign user out. And we'll have to create a function. Right now. Const sign user out. Well, to sign out is actually extremely
simple and straightforward. You guys won't have any words,
but this is basically with with Firebase there is a specific function
called sign out for press enter. It will automatically imported
from Firebase US. Let me just put this below
the use of the state and this function is as simple
as it can be. We're going to just say a contest actually to see a weight sign out
and we just have to pass sign over here. The other variable
that we have in our Firebase config file. So inside of this file over here and then it's going to actually sign
sign up. But what we want to do
is we want to try catch this so that we know if it's successful or not,
because sometimes it might not be right. So if there's any errors, we're
just going to console the error, this error,
but actually you call it error like this. But one thing to notice is that
if there's an error in signing out, this is what's going
to be handled. It's going to like immediately
leave this block and go to this run. So if there is no error,
by putting the right catch, we can assume that every line
after the weight sign out will mean that it has successfully logged out,
which means we have to do some cleanup. For example,
I want to clear the local storage because now we don't have a user signed in, right? So that information
in local storage is useless. And it should be clear,
not only that, but now I want to navigate towards not this way, I want to navigate towards the
the initial page, the log in page. And to do that,
all we have to do is just similar to what we've done already in the past, is
we have to import from React Road. Adam and we import the use navigate hook. And then over here we just const navigate is equal to use navigate. And then you guys should know
this should redirect us to this page. Let's check out to see if this working so you can see the styling for the button. I had put that in this SS but we should
check the, the actual application so we do have a user logged
in, as you can see over here. But if I click sign out, not only I get redirected back to the
login page, but this has been cleared. So I log in again and then I'll click this
and you should see that we're logged in again. One thing that we have to do, and it's probably the final thing we have to
do, is handle this thing over here, right? We have a bunch of expenses. It's a bunch of income,
but how are we going to do this? If you are interested in actually
practicing your skills, want to challenge you guys to do this on your own
and then come back to see if like, I mean, if you're able to do this,
you guys know what? What? I was supposed to be here, right? This should be the zero balance. So the net income and expenses, this should be just income
and this should be just the expenses. Well, try doing this on your own. If you succeed, then good job. Then check out my my version
and see how different they are. But if you want to just watch this, be
showing you guys how to do this right now. So in order to write this functionality, we're going to go back to the use get transactions. Hook I want to put that over here. Now, the reason
why I want to put this over here is because there's a couple of ways
to actually do this, which is kind of interesting. So you could create a table or collection
in your database to keep track of the total income,
total expenses and total and total balance, right. In general. And then every time there's a transaction for a specific person,
you could just add or subtract that value. But there's another approach,
which is easier because we don't have to have another collection. It might scale less properly
because it's something you're handling in the frontend,
but it's perfectly fine in my opinion. And this approach is the following. First of all, I want to create a state that is going to keep track
of all the information we need. So it's going to
be called transaction total transaction totals. I don't know if that English is correct,
but it's fine. So this is going to be actually an object,
not an array. And this object is going to contain
both the like the balance, which is going to start at 0.0, then the income
which is going to start a 0.0 as well, and the expenses
which is going to start as 0.0. Now I'm doing 0.0
because we do want it to look like this. It doesn't go zero zero
because of prettier, but 0.0 should be fine
because we also accept decimals. Right? Then what I want to do is I want to come over here and to where
we're dealing with our transactions. And if you recall this over here
should return a list. A snapshot is a list of all the documents
in this database, in this collection, where the IDs is equal to the user
ID who's logged in. So that's perfect for us
because we want to get the total income in the total expense
and the balance from that specific user. So all we have to do is manipulate
this data a little bit so that we can keep track
of those two pieces of information. So I can say
let total income equal to zero. We're initializing this variable variable
and I'm going to do the same thing with total expenses equal to zero. And then over here, after we push, right, we've done that part of like just adding them to the array
and listing the transactions. After that, I want to do a little bit
of a calculation. Well, if we're dealing with with a transaction type, I shouldn't type equal to an expense. So if this is an expense,
then what I want to do is I want to increase the total expenses
by the actual transaction type. So data transaction type are transaction amount. Sorry about that transaction amount. Well, if it's not an expense, it's
definitely an income. So I'm going to do the opposite. I'm going to do total income just like this. And this over here will be since
we're getting from an input, from an input like a reasonable input, it's actually
going to be represented as a string. So we do have to convert into a number
so that we can edit property. So I'm going to come over here,
turn this into a number as well, and this should be working fine. You'll see that in the end,
when this loop is done, we're going to basically
have the total income and total expenses as the correct values,
right for that specific user. Now what we can do is right after we set the transactions right, we can also set our transaction totals. So we'll say set transaction totals and we'll make it such that the balance, well, we haven't dealt with the balance
yet out for now, set it to zero, but then the total income
and total expenses will be both set over here. So total income as well. And what we do for the
balance is actually pretty simple, right? It's the net value. So what we can do is we can just
let the balance equal to total income minus total expenses. That's simple. I don't know. Economics. Simple math balance is equal to the income,
the positive minus the negative. Right. So what we have now is an object in a state containing the total balance,
the total expenses and the total income. And what that means
is that at the end over here, we now also return
back the transaction totals state and we'll come over here to our expense tracker component
and we will get back from use, get transactions,
the transaction totals as well. Now there's a couple of things
we want to do with transaction totals. So what I'd like to do
is I'll actually destruction the structure, the three values because I think it will be easier
to play around with them. So I'll set const equal to transaction
totals and similar to how we've been doing over here since it's an object,
I can just get the balance. The total income and the total expenses like this. I'm not sure why this values are
are not correctly being distributed. Let me take a look at this. Oh, it's called income, not total income. So I'm sorry about this, guys,
but it is should be expenses is equal to total expenses
and income is equal to total income. Sorry if you guys notice this first. If so, that's pretty good. But over here we just have to grab
the income and expenses. Perfect. Now what I need to do
is will come down here the bottom, and we'll first start
working with the balance. So with the balance, And first,
I'm actually going to leave the balance for later
our first work with the income. So for the income, what are we going to do
is we can delete the preset amount over here. We're going to leave the money
sign to be in front and over here we're just going to say income
literally just this. And you'll see that
now the income should appear over here. Write 187, which to be honest, it doesn't seem right. actually seems like it's adding
everything. Is it? Actually, it doesn't. But it's weird that it says 187. Right. I'll just put the expenses
and then check out to see what happened. But that was the income. Now, for the expenses,
we'll do the exact same thing. Let's check out to see
if the expenses is working. So we'll check over here. And it is not working. what does this mean? Well, we'll check out what we did wrong. This is actually a good exercise because
I've said this a bunch of times already. I enjoy it whenever I make a mistake
in a video like this because I can just show you guys how I debug. So it says total income equal to zero
two or expenses equal to zero. And it seems like we've been properly checking this in, properly increasing this amount. Let's test to see what the value of total expenses and total income seems to be after each iteration. So we'll say console.log total expenses
right next to total income after each loop will open up our console.log over here
and we'll check. So first it definitely checks
for the expense. 22 one is 57 and 87,
so it seems like it's increasing the income instead of the expenses. Yeah, because see 22 is the first one and then he treats 35 as a as an,
as an income and I'm making some mistake
that is really dumb. Well, I am I actually just noticed
and this is actually a good example
to why you should use TypeScript. I wrote transaction wrong
and you guys, you guys might have already figured this out,
but I literally wrote transactions wrong. So this should be transaction transaction type and I hope this works. Yeah, it does work. So if you got annoyed at me
because I was not seeing the mistake I made, I'm sorry, but this is debugging your time
and I hope you guys can see that even I can make a really dumb mistake
like this. But bottom line, we're now
seeing the expenses in the income. Then all we have left
is just to calculate the balance. And the balance will be pretty simple,
but also kind of interesting. We already have the value for balance,
but I want to show you guys what the problem with that is. I'm going to come over here
and put balance right and balance, it says correctly, $73, but balance
differently from income and expenses. It can actually be negative, right? Expenses is a negative. But when you say, oh, I have $80 of expenses, you never see or have -$80 of expenses. But if you have a negative balance,
you say, Oh, I have -$73. So the problem with this is the way
we structured, if I were to come over here and say that I went to McDonald's, right,
and I ordered $200 worth of maintenance and I added this transaction
and I would says that is -127. But the negative sign
is not in front of the money sign. Well, that's not that big of a deal. But I want to show you guys
how to fix that. And it's pretty simple, to be honest. You just come over here,
your first ask, Oh, is the balance is greater than or equal to zero? Because if it is, then I know for a fact it's positive
and I can just display the actual balance. But if it's not greater than or equal
to zero, that means it's negative. So I'll actually display an H2 tag
just like this, but I'll put the negative sign in front. And the problem with this yet
there's one thing more and one more thing I have to do. The problem with
this is because now it's double negative. So you have to make sure that the balance
is actually the number is positive. So multiply this number by negative one and you'll see that it now
correctly says the amount. I can also, for some reason work in McDonald's. So I'll put McDonald's salary
and I'll earn something that will make this positive $500, change this income
and you'll see that now it is positive. If I were to I don't know, let's pretend I got sued and I have to pay a settlement of,
uh, I don't know, an absurd amount right now. It's an expense. Let's add this. And yeah, I'm -39,627. Also, with the costs, I added this
cool thing where you can scroll if the information inside is overflowing,
that's pretty simple. You can check out the code as well. But yeah, there is definitely other things
you could add here. For example,
you could add the column over here, but those things, to be honest, I don't
I don't really care about that much. You can also clear this inputs
if you wanted to. That could be kind of cool, to be honest. I might do that right now
just because, I mean, you guys already here, I'll just show you
how to do this real quick. So to do that, all you had to do is go to the individual
inputs, set a value to them. So for example,
this is the description input. I set the value equal to the description
state. I'll do the same thing with the amount one but set it to the transaction
amount, right? And then whenever we actually add right,
we add a transaction at the end. I'll just set those two states
to be an empty string and that will kind of clear out that the input. Right? So I'll just do this and you'll see that
if I were to come over here and say, let's say I got I won the lottery, so lottery, I'll see that I won this amount right now, not only worked,
but it also cleared both inputs. I also just remembered something
that I still have to do. And I don't think you guys even notice
that this was missing. Is this the fact that if I close this
and I went over here and and opened it again, would see that although I am logged
in, it's asking me to sign in with Google again. And the reason for this mistake,
which is not really a mistake, is just because we're not redirecting
in case the user is already authenticated. If we recall,
when we created our local storage item, we actually created
a property called is off. Let me try to open this up. I don't know if I'll even get there. I can. It doesn't matter. You guys remember that I created
this property called Is off. It's literally in our code. So what I want to do
is I actually want to. Whenever
you go to the authentication page, I wanted to check to see if you were
already authenticated because if you are, then I want to redirect you to the expense
tracker page. Now, how do we get the information
if you're authenticated or not? Well, we import the the hook, right. So import from two slashes. Two slashes and then plugs use get user
info, import use get user info. We're going to const equal to use, get user info, and we're going to import
that is off variable. And there's one thing
that I wanted to show you guys. I've been showing you guys throughout
the whole video that with Victory Dom, you can navigate by calling this function
like this. But the problem with this is in this case,
how would I navigate my this right? How would I do that? Well,
there's a couple of ways of doing it. I could actually create a user effect over
here, write something like this and just check, oh, if is us, then call the navigate function. This would work. But there's another way. And I wanted to show you guys,
which is to actually use a component from where I tried it on
called the navigate component. So just this two ways
that you can actually do this and it's cool that I can do both of them and in their respective
use cases inside of this component. This component navigate is really simple. You just say, Oh, if is office true, then return the navigate component
and you can put a prop over here. Same too. And then you put the string saying Express
use tracker. It's basically the same thing,
but it serves for cases like this where you want to redirect
because of some sort of condition immediately when this specific component
has been rendered. Right.
So in this case, the condition is off. Is off is true. We don't even have to check
whatever is below here because we already want to navigate
towards this component and we can check that this works
because I was on the other page, right? I can even try to go to the other page,
but it will automatically redirect me back to this one. Right? So everything seems to be working. So yeah, that's that's basically it. The last thing I want to do is not related
to the code is just deploying this application so if you recall
in the beginning of the video we actually got some instructions
on how to deploy. The instructions included. We put it over here, included running
Firebase log in Firebase and it and Firebase Deploy. Like in the beginning of the video
I told you guys to install or install the the firebase Tools CLIA. We've done that already,
so we're not going to do that again. But if you haven't, I recommend trying the Firebase log in command
and see if you are logged. In my case, I'm already logged in. So now what we have to do
is we actually have to first create a build version of our project. If you've ever deployed
anything in the past, you know that that's a good thing for you to do. When you build. It will create this build folder
over here in your project. And when it's done, it kind of creates an optimized version
of your project inside of this folder, and this is what we're going
to actually send to Firebase to deploy. Since we've done that,
we're just going to run Firebase in it and it's actually going to start
asking us a bunch of questions. And this is where things
get a little bit confusing. But stick around with me
and you'll see how it's done. So basically, it's going to first ask, what features
do you want to set up for this directory? So there's a bunch of options over here, and the one I want is, well,
think about it this way. What do I want? I want to have fire story as an option. I want to have hosting as an option
when I have a bunch of those things right? But technically, what it's really asking
here is what I want to set up right now, right? So I want to set up hosting
and of the options, the one that I want is the first one,
the hosting configure files for Firebase Hosting and optionally
set up GitHub action deploys. So to choose
that I'm going to press space, it's going to become green, as you can see,
and then I want to press enter. Now it's going to ask to select select
an option. I'm even going to zoom in a little bit.
You guys can see everything better. It's going to say, Do you want to use
an existing project, Create a new project, add to an existing
Google Cloud platform project. But no, to be honest,
we just want to using an existing project because we already created it
in our console. So I'm choosing the first option
then it's going to list all of the options of projects
that we have inside of our application, and we have to choose which one
we wanted to deploy. So I know I have to actually
just have one one expense tracker. Let me just make sure the way we make sure
which project we're talking about is well, actually check out this thing
over here and the URL. It's the name of your project. This one ends with D one for E eight. So that's the one. So that's the one I'm going to choose. I'll come over here. I'll choose this one. Press enter. Then it's going to ask, Do you want to use public as your public directory? Yes, we've actually already
built this thing, so we're going to press enter,
then configure single page app. I'm just going to press enter
as the default option, then set automatic builds
and deploys that GitHub. I want to press yes for this because we want actually
we're going to set up our GitHub account such that whenever you push
any code into a GitHub repository, it will automatically trigger
a redeploy, meaning that if you make changes to your project
and you merged them into your main branch, it will automatically redeploy
for all of your users. That's how actual websites usually work. There's obviously more checking
and more stuff in the pipeline before going public, but in this case
it will look something very similar. then is going to ask, okay, the file
public slash index HMO already exists. Do you want to override it? I'm going to put no, I'm going
to press enter and it's going to open up the GitHub login for this application. It actually opened up
in a different monitor for me, but I have already connected my GitHub
account with my Firebase CLIA, so it's already done. But in our case might prompt up for you
to log in with with GitHub so that you connect both. And now what is asking is what GitHub
repository inside of our GitHub account do we want to basically
connect our Firebase project with? So we're going to go to GitHub right
now, GitHub dot com and we're going to open up.
This is my account. I'm going to create a new repository
right in front of you guys and click on new repository over here. I'm going to give it a name
as expense tracker Firebase React. I don't know, I'm just calling this
because this is the name of the repository for the code. You guys will probably have access
during the description. Then I'm just going to click
create repository. It's going to give us a bunch of options
as usual. When you deploy something, I'm going to actually open a visual Studio code
and I'm going to open up a new terminal. This is going to be the terminal
we're going to be using to deploy this app into a repository, right? So I'm going to run git init,
then I'm going to say git add dot, then I'm just going to copy
all of this stuff over here and paste it over there just like this. Hopefully
everything works out with GitHub. It seems to have worked out
and I refreshed this and you should see that
all the code is here. Now that our code is displayed
inside of this repository, we actually,
if we look back at the commands said by by far the fire, basically
it says that we need to enter here exactly in the format of a username
and slash a repository. What repository do we want to connect. So what it means is basically you have to
copy this part of the URL over here So all we have to do here is just paste
that information and then press enter. It's going to retrieve the information
from our repository and when it's done, it's going to ask,
okay, do you want to set up a workflow
to run a build script before ever deploy? Well, in this case,
we don't want to do that. So I'm going to press no or end
and we'll say no. Then it's going to say set up
automatically deployment to your site's life
channel when a PR is merged. So yes, we do want that. So I'm going to press enter, by the way. I press enter and right sometimes
because the the default option
is capitalized on this thing. So in this case, the why was capitalized. So yes, was the default option
and it was the one that we want. So that's pretty good. Finally, it's going to ask
what is the name of the GitHub branch associated with your site's life channel? Well, basically if you have multiple
branches, it's going to ask which one you want to actually be
the one that when everything is merged is going to trigger redeploy. In our case,
we only have one branch. So I'm just going to press enter because
by default it's already the main branch. And as you can see
it says Firebase Initialization complete. If all has worked so far,
this means that if I just run Firebase deploy, everything should be deployed
inside of our project. Let's check how I just press that on
and it seems like it is indeed working. We're going to click on the hosting
URL to see if it is working and let's see. Well, it's kind of empty right now. doesn't seem to be showing anything. But while that is loading,
I think there's no problem with it. And I think it's just a matter of like seconds between
before that actually starts working. Make sure we're going to call copy
the project console should don't know. This is where basically
the information related to your project and how it's running if it's deployed
or not, this is where you can see it. So, so far it seems that it's not working,
but it says that it has been deployed. okay guys so I tried to figure it out what
the problem was and it was a stupid one. It was my mistake. But I'm going to show you guys
what it was, so I want you to actually run Firebase
in it again and go through this again. But since you guys have already done
it, it's pretty quick. Choose hosting then on this part over here instead of
just going for your public directory to be public, actually choose, build
and this was my mistake. I forgot I ran your own build before
and then our project will actually be in the build folder,
not in the public one. So I'll just write, build, press, enter then for this
will just continue what we did before. We want to set that up. Build index that already exists. You want to overwrite? I'm going to press. No. And then it's going to ask
for authentication. Like we've said before,
we've already done it. It's also going to ask the again
for the GitHub account. I'm just going to do the same thing
for the GitHub repository pasted here. Press enter,
then it's going to connect again up and then it's going to ask
the same questions we've had before. And this for this I just put yes,
I think it's the same question as before. Now, initialization complete. Now finally, I'll just put Firebase
deploy, Press enter and it should be done. One thing to note, the reason
why I actually made this mistake is because Firebase deployment
seems to have changed. So if we do so, the changes that I had
before doesn't really work anymore. So just copy that link. And actually I already have it here. I'll refresh it
and then I can change meaning that it was deployed, but it's still blank,
so let's check this out. Can't read name. Okay. Yeah. But there seems to be a bug here. So. Inspector element console. Mm hmm. Says that. Can I get properties in all
every name from use get user info. Let's check this out. So I'm pretty sure I know where that is. I think somewhere this is where a name is, right? Yeah, I this thing over here
is actually a problem, because if local storage doesn't
have an item and it passes it, there won't be an item code
name to actually return. Right. And it's not just mean. If I delete a name over here and left it
like this, the error would say profile photo. It's just it's the first and then
it stopped looking at the other errors. So what I have to do here
is actually have to put a condition saying a fallback, saying that
if this returns null, it's still an object and I can
so that's destructor name from it. But the problem is that even if it's an empty object, it can try to destructor name
even though we won't exist in it. So this will fix the issue. I believe I'll save this run yarn build
and then remember that if you're going to deploy
right, you'll always have to yarn build because that's the version that Firebase
uses to actually host your project. And then I'm just going to run
Firebase Deploy now, the reason why I'm running Firebase
Deploy instead of just pushing to GitHub, which I will right now actually do it
right now is because to be honest, I just when you push to GitHub, it will,
I just have to fix this. So when you push again, it will trigger
a deployment, but it might take a bit. In my case, I just wanted a quick deploy to show
you guys that this is going to be working. I will refresh this over here. Hopefully, as you can see,
our project seems to be life. And the good thing is if I try to sign in
and I use the same email account I used in my testing, so like in the non live version,
the data should still be there. As you can see, it's still there because it's all connected
into the same database, right? And it seems to all be working. So this is basically it for the video. I really hope you guys enjoyed this video. Enjoy it. Please. Come on. Which one is next? Subscribe Because I'm posting,
I'm actually going to be posting once every two weeks. I believe the reason is I decided
to change the way I approach my videos. This video specifically is a little bit
longer and I kind of like that. The reason for that
is because if I make longer videos, I have a brand new group of videos
that I couldn't make before because of my fast paced schedule and a lot of the views you guys have been
asking me for years now, I couldn't make it
because I had to post every week, but now I'm going to have a lot more time
to do so. Not to mention I'm fully graduated
now from from university, so I'm going to be starting work full time. For those who don't know, I'm going
to be working for Twitch in about a month. So I believe I also have more time
because. I do think school takes more time
than full time work, which is crazy. But I will have more time
and I'll be making videos like this. This is also my first video after a hiatus
of almost of almost a month. And I'm really happy to be back. I'm really happy to be full on
devoted to this, and I'm really excited to produce
really good content for you guys. Again, if you're interested in check out
the code, it will all be the description. I wanted to thank Skillshare again
for sponsoring this video. I really enjoy the platform,
have been using it for years and have been working with them for years
now, so I really enjoy that. They gave me opportunity.
So that's basically it. I really hope it gets enjoyed it. And I see you guys next time.