Full Stack React & Firebase Tutorial - Build a social media app

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Hi. In this series, we're going to be learning how to use react and Firebase to create a fully featured social media application. So application will let us sign up by filling the signup form right here, which will be validated once it's submitted. And if all the info is valid, an account will be created for us and we will be redirected to the homepage. In the homepage, we can view posts, which are called screams in this platform, we can see comments and the number of likes and scream has, we can also upload an image that will be our profile picture that will be stored in our Firebase Storage bucket. We can also update our profile by adding details about ourselves such as a bio, our location, and our personal or professional website. Once these are submitted, they are validated. And once they're valid, these details will be publicly visible to other users of the application. We can also always edit them again, if we're not happy. We can like other people's screams, we can make as many screens as we want. We can of course, post comments to screams. And they will be reflected immediately, as we will see here. And we can of course post our own screens by pressing the plus button at the top and type in stuff, as you see me here type very slowly, and pressing Submit. And once we submit a post, it will immediately show up on the application. And we can of course like our own post, as absurd as you or I might think that is we can of course post as many screens as we want. And if we make a mistake, we can also delete the screen, we using the delete button will show us a screen, a confirm dial just to make sure that we don't accidentally delete them, we can see other users pages and their posts. And if we do log out right now. And if we do log in as the other user that we just liked and commented to the screen, we will see a bunch of notifications informing us of exactly just that. And if we click on any notification, it will take us to that post that the notification was talking about. As I mentioned, our app will use Firebase as a back end. And this right here is the database. And we can see it update in real time as we add screens, which is going to be super useful when we are developing our app, we can see our database collections, things like screams, notifications and comments right here. And all the other collections. We can also see information about our users and stuff like that. We will also be using Redux for managing our application wide state, which will hold the data needed in our react application. This right here is the Redux dev tools, which will be super useful later when we are developing our app, it will make it easier to see what's happening in our application, what data we have, and what errors we have. And this will all be you clear when we dive into Redux later. Before we start anything, I just want to give a quick run through the tools that we're going to be using. Starting with the big one, the front end library of choice that we're going to be using is react. React is a great framework for building component based web applications. Even though it's technically not frameworks, the library, we will be complementing it with things like react router, Dom and axios, and a couple of other libraries that will make it feel like a complete framework and will allow us to do everything that we need to do. So yeah, it's a great library for building components, building templates for our pages, and building dynamic markup for our for our application pages. Now, I do have a big disclaimer though. If you are not familiar with react a an absolute newbie and have never touched react, this series is not for you. I recommend that you learn the basics of react and get comfortable with it. And of course, be comfortable writing JavaScript, and then come back to the series and then you will do some proper learning. If you're familiar with react, then you're right at home. So next thing is Firebase. Firebase is a great platform as a service, we will use it as our back end. It offers us multiple services, of which we will use Cloud firestore as a database. It's a real time database. And it gives us two access to a couple of really cool functionalities to use a no SQL database document base, which we'll see later. Next thing is Cloud Functions we're going to be we're not going to be writing like a Node JS. Like server code. Even though Cloud Functions are based on address, we will be writing a couple of functions that will be run whenever we need to run them. Next thing is authentication. We're going to be using Firebase authentication to register our users and log them in and get authentication tokens and a bunch of other cool stuff. And we will also use their cloud storage service to store our profile images that are submitted by our users. Next thing is material UI, which is something that I've come to learn and really love recently. Material UI is one of the best if not the best react implementation of Google material design standards. Think of Google material design is like a CSS framework. It's a couple of standards for designing user interfaces. It's really cool. I really like material UI, they have amazing documentation, which makes learning and implementing it really smooth sailing. Next thing is this might come as a surprise to some of you, we're going to be using Express. I know we're not using Node JS. But Cloud Functions are essentially no JS code that is executed on demand. So we don't need to use Express, but it's better. I think, in my opinion, if we do because it makes the code much cleaner. As you will see later, it will help us group our code and separate our routes properly, and handle our requests and send our response properly in writing our API. Last but not least, for sure, is Redux. So our application is going to have a lot of components. And they're going to need to access data. And best practices when you have a lot of components. And a lot of them need to access data is to not pass data from one to the other, aka prop drilling, I will post a link to a really cool post that explains why Redux is a thing and why people use it instead of just passing props around. Redux makes it really seamless to have an application wide state that all the components can separately talk to and fetch data and send data to if needed. So yeah, we will of course be diving deeper into the definitions and functionalities of each of these tools. When we work with them separately, I just wanted to quickly show you what this series is going to be using. So in this video, we're going to start to work on our back end by creating some of the Cloud Functions that will give us access to our database. And that will give users access to the Authentication Service, etc. So before going to start, I'm going to go over some of the prerequisites that you need to work on this project. So number one is no js, we need this just to use NPM for installing some of the packages. Number two will be VS code. Now this is optional, but I recommend VS code is the best text editor for me out there. Even atom and sublime are pretty good as well. But some of the extensions of VS code are really, really, really good. Number three is postman. If you don't have it, download it, we're going to be using this to run an API request to test our API, either Windows, Mac OS, or Linux, all download links are available. I want to show you something on VS code, just so that we are on the same page, I will be using bracket pair colorizer, which will color some of the brackets differently that will make our code easier, easier to read. prettier, which formats the code each time I save, so that we don't have to indent and yes seven, React Redux etc. snippets, which will give us access to some of the snippets that would generate code without without us having to type all of it. Okay, that's it with the prerequisites. So let's actually start creating our project. So here, and firebase.google.com. Let's go to our console by clicking go to console. And as our console loads, now we can create our project, click Add project. And let's call this social ape. Because that's what we all are at the end of the day, I guess. Select your region and country. I'm in the UK. So I'm going to select United Kingdom, select the server that is closest to you. To me, it's your request, and hit they accept and create your project. This will now create a basic Firebase project with everything initialized. Okay, now that it's done, click Continue. First thing I want to do, let's go to functions. And once that loads, let's click get started, which gives us some instructions tells us to install this package. Let's click continue and finish. We'll do this separately. Okay. Let's go to our desktop or whatever, really. And I'm going to use the basic command line because it's interactive and not good bash. Here, let's install that package. So npm install dash g Firebase dash tools, which will give us access to the Firebase command. line interface that will let us create our functions and deploy them to our application. And I'll be back once this is done installing. Okay, now that it's done installing, by the way, you can just ignore this message thing. It's not important, we can run Firebase login, so that we can authenticate today it would know who we are. And for me, it says, I'm already logged in for you, maybe it will just pop up a browser window, and you just select your Google account. So here, I'm going to go to my desktop. And I'm going to create a directory called social Pape dash functions. Going to CD into that. And here, we're going to run Firebase and knit for initialize, which will create our project, we want to proceed Yes, and hit space on functions. And this is all that we're going to select for now as from services, and here you choose from your projects, choose the project that we just created, it's going to ask us to use JavaScript or TypeScript, we're going to use JavaScript and ies Linton, I'm going to say no to this. And let's say yes to installing packages, which will now install all the dependencies that we need, I think, like two or three dependencies. So I'll be back once this is done. Okay, now this, this is done. If you have Visual Studio code, you can run the command code dot, which will open this in VS code. And there we go. So this is what we get a get ignore file, and a Firebase config file that has our project ID, we go to the folder functions to index dot j, s, this is where our functions will sit. And as you can see if we uncomment this, this is a basic hello world function that comes shipped with Firebase. Let's change this text to say, Hello world. And oops, hello, world. Let's open up the command line. And let's run Firebase deploy. This will now deploy this function so that we can test it and see if everything is working fine. Funny that our hello world function didn't actually have hello world as the return. Okay, so now we will deploy our function to our, to our functions, and it will give us an endpoint which we can call to see the response from that function. And if you're, by any means familiar with node, this, the syntax of request response and a callback should be familiar to you. If not, we will work with a new you will get familiar with it. Okay, so now that our function is deployed, we get an endpoint right here. So let's copy this. And let's open up postman. And let's see if this is working. To wait for postman to open. Let's put these side by side. So let's base this on. Let's hit send. And indeed, it says hello world. So we're up and running. Okay, let's do something a bit more complicated than that. Let's go to our project. We're here to close these windows. Let's go to database and initialize our database. So we click CREATE DATABASE. And it asks us whether to start in locked mode, or test mode, which these are like database access rules that give us access to read or write some of the documents for now let's go in test mode, which will leave all resources open for everyone to edit, which is crazy, but we're not in production yet. So it's fine. As well wait for it to set up everything. Now we can actually start creating some documents in our database. Let's create the first collection which will hold our posts which are screams if you remember, so screams is the collection name. And let's actually create our first document. This will have a field called user handle, which will determine which will let us determine which user submitted this last type user. Now this user doesn't exist yet, but let's just roll with it for now. The body of the scream should say first scream are under no. And this will have a created add field. This will be a timestamp. Let's give it the date of today. And it was posted at midnight because why not? And now this will create our first screen. Let's actually create another one quickly Here's a user handle again, it's the same user. And it's got the body field, this should say, second scream. And let's add the created field as timestamp, and give it the date of today. Let's say this was created at 1am. So let's save. Now we have a database with a collection of screams with two documents in it. Now, let's try to whoops, yep, let's try to actually fetch these posts from the database. So let's create another function. We'll call this exports dot get screams. And this will be from the functions namespace. And from the HTTPS area, I guess. And we will use honor requests, we will use some other handles some other functions later. But for now, we'll stick with on request, oops. So this will be will take a request and a response. And these are arguments so we can name them however we want. And our function now needs access to the database, we will be using something called the Admin SDK, we will import that by doing constant admin, we already have the package installed, let's do require. As you notice, here, we're not doing import from this is not your sixth because this is this is basically no JS code to do require Firebase admin. And to use the admin, we need to initialize our application. So we'll just do admin dot initialize app. And usually, we would pass an application but this project already knows that this is our ID of our application. So we just do it like this. And now we have access to the admin object, we can do admin dot firestore dot collection. And now we give it the name of the collection that we want to access. By the way, all of this is in the documentation. If you want to see quickly, we can go to Firebase, actually, we can just google just duplicate this thing, just google Firebase firestore. And by the way, I really recommend checking out the Firebase documentation that really, really comprehensive so if we go to fire, cloud firestore, and we go to read data, get data once. And let me change this for readability. And I believe, yeah, it's right here. So to get all documents in a collection, you run DB dot collection, which in this case is admin Docker dot firestore. And you give the name of the collection, and you just run dot get, which returns a promise, which holds a query snapshot. And in that query snapshot, we have an array of documents, and I'll show you how we're going to fetch that fetch those. But let's actually maximize this. So the collection is screams. And let's do dot get. And then we do dot, then we have some data. And if you hover over here, you see that this whoops, this should not be any, you should give us a type. For some reason, it doesn't. Okay, let's just go with it for now. So we say data. Yeah, now it does. So this is a query snapshot type, which has a Doc's in it. So if you do data dot Doc's, you'll see it has a property Doc's which has an array of documents, snapshots, which are documents, so we can do data dot for each document. And we need to store them in something. So let's initialize an array called screams, which is an empty and empty for now. Here for each document, we want to do screams dot push. And we don't just do Doc, because this is just a reference, we do doc dot data, which is a function that returns the data that's inside the document. And now this after this for loop, the screen should be populated with the data of the screams that we have. Now we need to return them. So let's do return response dot JSON to return it as a JSON object. And let's do screams. And let's put a colon and of course this returns a promise it will be good practice to catch any errors that might happen. So we do catch error. And if any error happens, we just want to console. log it to the console using console error. error. Like this. Now we hit save. And now we can do Firebase deploy again. And this will deploy our function. And we can test if it's actually working. Okay, now that our function is deployed, we can actually test it. So let's copy this endpoint. And let's go to postman. Let's make this bigger. And let's paste our endpoint here, and hit send. And this should bring up the documents that we just created. And it does. So this is the first document. Rather, this is the second document, which says second screen. And this is the first one which says first scream are perfect. So so this is for getting documents, let's create another function for actually creating documents. So let's do exports dot. Let's call this create, scream. And we can actually just copy this, like this, remove the code inside of it. And here, we're going to get a request body because this should be a POST request. So let's initialize our screen, let's call this new screen. And this will have a body of request, and our request will have a body. And don't get confused this, this body is the body of the request. And we're going to do dot body, which is a property in the body of the request. And this will make sense in a second. And the user handle will be request dot body dot user handle. And we need a created art. So as to create art equals I think this is admin, dot firestore dot timestamp timestamp that will use a function called from date, which will create a timestamp from a normal JavaScript date object. So we do new day, we'll pass it a new date. And now we have our object, we need to persist it in our database. So let's do admin dot firestore dot collection. And same collection screams. This time, we're going to use a function called add, which will take a JSON object and add it to our database. And the object in this case is our new scream object. And this again, returns a promise. So we do thought then this will give us a document reference as a response, which is actually which we're not going to do anything with this document reference. So we need we can just do this, because we're not going to do anything. Actually we are the scope that document reference. Now, if we are here, that means the document has been created. So we can return a response or concept JSON. And this will have a message that will say, I'm going to put backticks, because we're going to put a variable inside of here, I will say document. And let's do dollar sign curly braces to pass the ID of the document, which is a property in a document reference type, we'll just do doc.id. And we need to say create, we're going to say created successfully. Now, if there was an error, okay to catch error, for some reason, or do console dot, actually, let's return a response. So we will do rest rest dot JSON. And by actually not, because there was an error, we need to change the status code will shouldn't return the status code of 200. Which means success. Let's do dot status. And let's give a status code of 500. Because this is a server error. And let's give a JSON object that will have a error, prop property or key. And this will say something went wrong. And let's actually console error it as well. Okay, so let's save. Now we can run Firebase deploy and test it. There's nothing wrong with that. But deployment takes some time, we can instead run Firebase, which will serve our application locally, which is so much faster and will give us the ability to save and then immediately serve again and we don't have to deploy each time we make a change and we want to test. So now this is gonna serve locally. A using our machines server Give us the endpoint. So let's take the Create scream endpoint, as you can see, says localhost instead of the endpoint that we had earlier, and open up a new tab. And let's test this, let's change the type of the request to the port to a post request. And let's give it a body, we're going to click raw, and select application slash JSON. And let's give this a body of new scream. And let's give this a user handle of a say knew less than the request. And, and it says document something, something created successfully. And if we go to our Firebase database, and we check, I don't know why I click that it shows without us reloading, and there we go, our new screen is here. And what's beautiful about this, put them side by side. And we say new screen too. And we click Send, it updates in real time. And we see oops, we see new screen too. Fantastic. Now, we shouldn't there's a problem here, which is that if I would send a get request to this, of course, without a body, it will say we have an error, like a server error, when actually this is not a server, this is a client, we shouldn't send a get request to a route that is meant for a POST request. We can prevent this by doing this. So we can say if request, oops, if request dot method does not equal post, we should stop here and return a response. So res dot status, it's not gonna be 500, there's going to be 400, which means this is a problem from the client. This is a bad request, as they send a Jason with an error that says, method not allowed. Now, this will solve the problem of not having to answer to a get request. So if we go to postman, and click Send, this time, it will say method not allowed with an error code, rather a status code of 400. So you can start to see how this is coming together and how we can send the request to fetch data send request to persist data. And this is obviously just the start, we're gonna have so much more. In next in the next video, we're going to start to implement express to so that we don't have to say this f request method on each request, and we can group our requests and handle them so much better use an Express. So let's install now Express and make this code look much better than it does now. So one problem with having our functions structured like this, is that when we want to have two endpoints of our API, point at the same name of the endpoint, but handle two different functionalities, we would have to put everything in one function and check the request method and respond accordingly, which doesn't look really good. So this is, this is one of the things that Express is going to help us with, okay, so let's install Express. Let's go to the console and make sure that we are in the functions folder, CD functions, and run npm install, dash dash save, save, Express. And once it's installed, we can actually start bringing it in. And that's installed. Let's do const. Express, equals require Express. And when you have to initialize the app, let's do const. App equals Express and call it like a function, because that's what it is. Let's remove this comment and this hello world function. We don't need them anymore. And let's see how we can change this route. So instead of get screams, we can actually copy this code that's inside of the get screens route, and get rid of this. And we can do app dot get. And we do slash screens. Because the first parameter of this function is the name of the route. And the second one is the handler, which takes a request and a response, similar to what we did like earlier. And here we're going to paste back the code that we had. And now this on its own will not do the trick, we need to tell Firebase that this app is the container for all our routes. Or actually the routes that are in the app. So we can do exports. And this is one of the things that that express will let us do, because what we want to have is one of the best practices for having an API is if we, let's say, have an endpoint, HTTPS, and let's say our base URL is called base URL Comm. We don't want something like this straight away slash scrims. Because it's good practice to have slash API and slash something. Because on the actual base URL itself, you might have your website. But when you do slash API slash, whatever, you can have your API there. And some cases, they do API dot base URL, but it's just different conventions. So we want to this prefix. So what I'm going to do now is that we're going to do exports dot API equals functions.https.on request. And here, instead of passing one route and one function, we just pass our app. And this will automatically turn into multiple routes. And now if we save and when we deploy, so we run Firebase deploy. It should prompt us a, it should ask us that, whether we're sure we're going to delete the get screens function, because we just deleted that code. Yes, it does, we will say yes, delete HelloWorld and get screamed because we don't need them anymore. Okay, now that it's deployed, we can actually go to our Firebase console, go to functions, make sure you're on that project. And there we go, we have this one function called API. And we have create screen and the other ones that we created are gone. Okay, so let's actually test this. So we go to postman. And I believe, well, we will not go to localhost because we didn't do a serve. So let's actually copy this. Oops, let's go to here and copy this endpoint. Yep, from here and go to postman. And if we take this, we have to add our actual endpoint, which is screams as we set it to be. And we send a get request. And we wait for it. And there we go, we get our screams. And now if we send a POST request, it should fail. And it does fail. And it says that the route was not found, which is cool, because so now we don't have to do this thing where we do if request method equals post, don't send an error, the like, express takes care of that. Okay, so let's change the Create screen route as well. So what we're going to do is actually just delete this part, or just right up dot post. And the route would be slash scream. And this is the handler. And here, I think everything is fine. We don't check if it's a post, because this is automatically doing that. And let's leave everything as is for now. And actually, instead of deploying, let's just serve so that we can test it locally, we don't have to deploy. So we run Firebase serve. So nowadays served and by the way, if you get a warning that your node version is higher than the one that Google Cloud Functions support, don't worry about that. As long as you write your code that is compatible with node six, and you don't use any features that are not supported by node six, you should be fine. So let's copy this. And let's go to postman. Oops, not wrong, postman. let's paste this here, because now we're on the localhost. And if we leave this as a POST request, and we add scream without an S, and we give it a request body, and this request body will have a body new scream, I think three, we didn't submit three, and the user handle and I say, Johnny Yeah, that's it. If we send it should successfully create a screen. And yes, document something something created successfully. And if we go to our database just to make sure. And, or Zed there is so screen three by Johnny. Brilliant. Okay, so let's go here. Let's actually fix up the screams route. What I want to do is that on whenever we return a scream, I want to return its ID as well and you'll see later why we actually need it. So here, instead of pushing all what's inside of that screen, let's push an object. And this will have a scream ID. And we will take this from doc.id. That's the property that the doc document, reference, or snapshot, rather has access to get the body, which is Doc, sadly, this is node six. So we cannot use the like, maybe some of you are thinking, why don't we just do this? Like doc dot data, which is called a spread operator and just spread all those properties. But because this is node six, this feature is not yet supported. So we have to do we have to do them one by one. So bodies doc dot data dot body, and user handle is doc dot data. dot whoops, though, use a handle. What else do we have created art? Is dog data, dog created art? Think this is it? Yeah, this is okay. So if we save now, when we get the screams, forgot to postman when we get the screams. So let's add an s here, make this a get request and remove the body. We send this request, because we're still serving, it should update. And there we go, we get the scream ID as part of our screen. Cool. Now let's change something because there's a problem here, we want to order our function, our screams, and we want to get the latest one first. So let's actually ordered them by date. And we can do that by after collection screams let's chain a method called order by. And let's pass the property of created at make sure you don't misspell anything. And this by default takes an ascending order. But we want descending, we want the latest one to be first. So let's hit Ctrl. Save. And we go and we send this request. And we should get the latest screen first. And we do the one we just submitted earlier. Brilliant. Now one thing I want to change as well is that these created art, I don't want to use the Firebase timestamp type, let's just use a normal date string, because that's recognized in JavaScript. And we can format it however we want. We want. So here, when we create the scream, I don't want to use the timestamp thing anymore thing anymore, let's just use new date. And let's just transform this into an ISO string. So dot new data.to ISO string. And it's a function. So this will make it into a string. And let's let me actually do that do something, let's create a file called DB schema. And this, by the way, has no implications whatsoever on our code is just something that I like to do, still let DB equal. Here, we're going to write how our data is going to look like, just as a reference thing, we're not going to use this file in anything. So I want each screen to have actually, in the database, it's not going to have scream ID, we just returned that from our code, it's going to have a user handle though, which we will use to identify who is the owner of this screen. Let's make this an object like this. Like this, okay, it's gonna have a user handle, and let's give this a dummy value of user, it's gonna have a body give this a dummy value of this is the scream, body. And it's gonna have a created at, and this is an ISO string. Now let's actually quickly like generate one for this do new date, to ISO string, not ISO and string, ISO string. Let's copy this, I know you don't have to do this. But it just, I think it's a good practice as a reference point, you don't have to open Firebase each time. One other property that we get one or two other properties, actually we're gonna have, we're gonna have like count, she's gonna be a number, let's say five. And we're gonna have common count. Now, this is good practice, because each time we get a scream, we don't want to as well check the comments that have the ID of the scream and count them and return that number because Firebase charges you on the amount of reads that you do So you're trying to minimize the amount of reads that you execute each time a user sends a request. So if you store these here already, you will avoid too many reads on your database and be charged less. Okay, so let's, let's just leave this for now. So this is what our screens would look like. And yeah, okay, so this is, let's test this screen, this post screen. Let's make sure it's still working. So let's send a let's, let's open up a new tab. So we don't have to type the URL again. Okay, so post, I'm gonna have a body of type application Jason. Let's give this a body of new scream 400. I don't feel creative right now. Use the handle of j Jane. And we send this request, oops, not screams scream. We send this post request. And there we go. We get document, something Something was created. Let's go to our database. And now we see the new one. And when is it the new screen for another created that is a string instead of a timestamp? Cool. Okay, so I think this is it for this video. Oh, actually, one, one thing that I want to add, for those of you that are not in America, and you're wondering why your functions are being deployed to where is it to us central instead of Europe. By default, Firebase deploys to us zone US Central one. Now, this is a bit of a problem, because it's going to add, like 300 to 400 milliseconds of latency on each request. Maybe it's not a problem right now in testing, but later in production, this is going to slow down your application. So if you are like me, in Europe, and you want to change deployment region, you just chain after functions here, you chain, the method region, and you specify the string, the name of the region, in my case, it's going to be Europe, dash, West one. And by the way, you can go to Google Docs, Google Firebase documentations, to find all the regions available. If you're in America, this doesn't apply to you just leave it as is. By changing this next time we deploy, it can actually be deployed to the zone Europe, West one. In this video, we're going to start to work on authentication. And on signing up users. In particular, let's go to our project dashboard. Let's go to authentication and enable it by clicking here setup sign in method. And here on email slash password, let's enable it and click Save. Let's go to our project settings. And let's go here your apps. And let's grab this config object. And let's go to our project. Now, we're going to be using the Firebase library, which is a actually a client library. But we're going to use it to sign in and sign up our users and get authentication tokens. So let's CD into functions. And let's run npm install dash dash safe Firebase. Okay, so let's initialize our Firebase application. This is important. So const, Firebase equals require fire base. And let's do Firebase dot initialize up. And we need to pass it config object. Let's do const. And let's paste in our config actually not var const. And let's take this config and pass it to as the argument to initialize up so that Firebase knows which app we're talking about. Let's actually make this Express line. Mix Express into one line by doing require Express and calling it on the same line. I think it just looks neater like this and let's put it up here. Let's create our signup route. Let's delete this comment. replace it with another comment saying sign up route. And this would be a post route. So app dot post. It will be slash signup. And the owner is gonna have a handler so request responses the arguments. And now we need to extract the form data from our request body. So let's do const new user equals an object. It's gonna have an email. If you remember our form has an email password Confirm Password and handle field. So as to email equals request dot body, dot email. comma, and let's copy this line and paste it three more times, select Email, Ctrl, D undo password, select Email, control the Confirm Password, and handle. We're not gonna validate the data for now. But let's write a to do here, validate data. And let's sign up our user. So let's use the Firebase package we installed Firebase dot auth as a function like this dot create user with email and password. And let's pass it exactly that. So new user dot email. And the second argument will be new use of password. This returns a promise so as to dot then data, which I think it's credentials as user credentials, so let's do it. If we are here, that means we've successfully registered so let's pretend a response response dot status of actually 201, which means a resource created as give a JSON object with a message with a template string, because we need to use a variable, let's say user. And let's do dollar sign curly braces to use a variable data dot user dot UID stands for user ID. And let's say signed up successfully. And course, let's catch any potential errors. And let's console error, the error. And let's return res dot status 500 oops, 500 server error. And it's gonna have a JSON with an error. Let's pass the error code. Let's return it in case there's any error. Let's save. Let's run Firebase. So and see if this is working. Let's copy this endpoint. Let's go to postman actually already have it. So let's do slash sign up instead of screams. And it's going to be a POST request. That's gonna have a body of type application JSON. So we're gonna have an email, I'd say this is user@gmail.com. We're gonna have a password of 123456. Oops, we're gonna have a Confirm Password, which does, which does nothing right now. But it will later 123456. And the handle, which is going to be user, so listen, this request. How do we get user, the ID of the user signed up successfully, and we get our code of 201. Cool. So if we go to our Firebase project, let's close this. Let's go to authentication. And there we go. We got our user with this user ID right here. Let's copy this user ID. And I'll tell you why in a second. What we need to do right now is that Firebase by default, doesn't allow us to store more information in about our users in the authentication collection. But what we can do manually is we can create, of course, right now manually, but later programmatically, we can create a collection here, we call it users. And this will store documents for each user, we will have one document that holds extra details that we need, such as the handle, and later, like a bio image URL, any extra details that you want to add. So And the key thing that I want to do here is that our users, of course, by default, because of Firebase, even though we can change this, but by default, each user is rich, each email is restricted to one user. So the email has to be unique. But we want to also have the handle as a unique thing, like, of course, because this website is kind of like a copy of Twitter. So our handles will be unique. So we can use our handles as the ID. So here, let's not to do auto ID. And let's give the ID of the user that we just created, which is user as the document ID. And here we're going to have user ID key. and the value of that is the ID we just copied. We're going to have a created art. And let's give this a timestamp the date today and say I don't know midnight doesn't matter. Let's add another field. This is gonna hold, what's this hold? Actually? Yeah, let's, let's put the email actually. Because if we need it, we're gonna have it here. So user at email, calm. I think this is all we have for now. So let's save. So now what we need to do each time someone signs up, we need to check this collection. And we need to make sure that this handle is not taken. So if right now if someone tries to sign up with a handle of user, or the desired behavior should be, you cannot sign up because this handle is already taken. And if they tried to sign up with the same email, Firebase will automatically give them the error. So let's actually write the code that checks for the handle being unique. Let's look at our DB dot. Actually, we don't have DB yet. Okay, let's change something. I saw this in the in the Firebase documentations. And I like it, let's do db, db equals admin dot fire store as a function like this. And wherever we need firestore, we just do db.so. Let's replace where they will find admin dot firestore. Like this, we'll replace it with DB because that makes more sense. So dB. And there we go. Okay, so in our signup route, we need to do DB dot collection, users dot document. Actually, we can do document without collection. So let's do DB dot document. And we need to pass it the path. So let's do a template string. And the past will be slash users for the collection. And the document will be as the dollar sign curly braces, new user dot handle. And let's do dot get. Of course, this returns a promise. And this will hold a as we see here documents snapshot Yes, document snapshot. So doc. And the way fibers works, even if this document doesn't exist, we'll have a snapshot. So what we need to do is we need to have a conditional here, say if doc dot exists, which is a Boolean, if this document exists, it's true. So if this document exists, then this is a problem because this handle is already taken. So let's return ress dot status of let's give 400 bad request. And let's give a JSON response. And the way we're going to structure our react app is that we're going to return a not an array an object containing errors. And for If the error pertains to any field, let's say the error pertains to the email, the errors name will be email. So in this case, the errors name will be handled, and the message will be this handle is already taken. Alright. And if this document doesn't exist, then cool. Let's create this user. So let's do here. So let's do Firebase. So let's do this Firebase dot all of this Firebase Auth, create user with email and password, new user email and this. But since we're already in a then block, we need to return this return. So we return this and then we chain another dot then. So that we will have the result or like the return promise from this call here. Will which will hold data as to here. Now this, if we get here, that means we have our user created. What we need to do now is I want to return an access token and authentication token to our user so that the user will later use to request more data. So we can do that by we know that in data here, we have access to the ID. So let's do user ID equals data dot user dot UID for user ID. And we can do data dot actually user ID, or is it user ID. Actually, we can even call it on the user itself. We don't need this. So we can do data dot user dot get ID token. Right now, it's not recognizing the, the type for some reason, but this should work. Get ID token. And this, this actually is a returns a promise. So let's do return like this. And you're like this and then let's chain another dot then and this will have token, so token, don't know why the types are not being returned, being displayed properly. But let's just go with it. Let's return the token. So let's return a response to JSON. Let's give the status again of 201. json token, we can just say token like this because the name of the property and the name of the value are the same sort of token like this should have the value of our token. Okay, let's delete this code here. And let's do a dot catch error. In case any error happens. Console dot error, the error and return as a response res dot status 500. json with an error, error dot code. Cool. Okay. Let's actually let's not put them side by side, let's run the same. Let's actually register a new user. So let's say new att email, same password and the handle is new. This should return us a token. And it does. So we have an access token right now. And this we will use to use whenever we need to access a router that is protected. Okay, let's try to actually register a user that already exists. So let's send the same request. So send we should get and there we go. We get an internal server or email already exists. Okay, so we shouldn't this shouldn't be happening we shouldn't get Actually no, this should be happening because it's the error from here. So let's handle it here. We want we don't want to return like this. We want to check if the code of the error is this code exactly here. That means it's not a server error is just actually, it is a client error, technically. So what we need to do here, we can do if error code, no code equals the string off email already in use, we need to return. Yeah, I think 400 less give a res dot status 400 dot JSON. And the error pertains to email. So as the email, we say, email is already in use. And if it's anything else, so else return this. And do we do we handle any other errors? I think we don't. Okay, so let's go to postman again. Listen, this request. Cool. ml is already in use. Now, we haven't yet created a field for this, we need to create a new field a document for our user whenever the they register. So let's do that. So right here, before we get the token, do we do it before we get started? Or should we don't we don't return this token here. So let's store it in a variable. Let's do here. Let's token initialize token here. And then here we have a student token equals token. And here instead of returning a response, let's, let's, let's do const. user credentials. equals and let's create our user document. So this will have a handle of new user dot handle. And we will have the email of new user dot email. And we will have created that which will be new date to ISO. Why do I always type the end after ISO? Okay, the ISO string, make sure you didn't misspell anything. And we need the user ID here. Us user ID or actually how do we access the user ID, we need to put the user ID as well in a variable so that we can access it. So let's declare the user ID here. And we have access to it here. So let's do user ID equals data dot user dot UID. And then we use we use oops, on this user ID We can just do this, because it's the same name. Okay, here we are. Now we need to persist these credentials into a document in our collection in our users collection. So we need to do DB dot document. And this will be in the users collection. Don't forget, by the way, thing, template literal string, slash user slash. And we'll give it we'll give it the handle as the document ID. So this will be new user handle. And we need to do dot set, which creates the document, unlike get, so let's pass this user credentials. All this returns a promise, I keep forgetting. So to return it. And then let's do yet again, another than promise you, I'm pretty sure this is the last then what do we get? We get some data here. What type of data is is the right result, this is actually useless. So let's just not even use it. Okay, return rest rez dot JSON. dot status, let's give the status. I don't I can just return 200. But I just like to return to a one once something is created. So status to a one JSON. And we need the token. So token. Yeah, this will work because it's the same name. Yeah, same name that property. And let's save. Let's actually, let me delete this. Let's delete the entire document or the entire collection. And let's delete these two users. Because I don't want to keep coming up with new emails. Okay, let's test this out. Make sure we saved we did. Or I did make sure you save as well. Let's do this as user again. user has to be the first one. Okay, sent Let's cross our fingers. And hope for a token and we get to a one button empty object. Interesting. Let's go here. Refresh. We get our user we go to the database. Users collection has been created cool. And the ID is user. And we have the details here. Everything is fine. But why don't we get the token back? Okay, so the problem was variable naming ambiguity. I named this token and this was token as well. Okay, so this is token now. And then I renamed the return from the promise to ID token and then assigned token, this token to this ID token, and then here as the response return token, which will hold the value of this. And if we test this, we go here and we do new five, I don't know, new five, and we post and we get the token back cool. In this video, we're going to be implementing validation to validate the data that's coming in and making sure that it's valid before we do anything related to our database. And we're also going to write a login route where users can log in. The reason one of the reasons why we need validation is that, for example, if I would do this, I'll give an empty email, I'll give a handle that exists, it would already go and check, oops, I need to run Firebase serve. If I would send data without an email, but with a handle that exists, it will already go because of how our code is structured, check whether this handle is taken or not, instead of just stopping here and saying that the email must not be must not be empty. So if you would give as well, no handle, he would. I don't even know I would would do which is give us like some word error like this, I guess. Yeah, the value of the argument or something like this, but we need to just validate everything ourselves and return errors accordingly. So yeah, the document path. Yeah, it was. We gave an empty string right here and it caused the problem. Okay. So what we need to do right now is we need to follow the each field. What we want to do is that we need to make sure that email is not empty and email is actually in a valid email address, and password and confirm password and handle all of them. We need to make sure they're not empty and We need to make sure that the password and the Confirm Password match saw the same value. Okay, so let's start implementing. So let's start working on the email. So we need to make sure that it's not empty, let's write a helper function that lets us determine whether a string is empty or not. So let's do const is empty, which is a function that takes a string and does the following. So it does if string dot trim, oops, not string dot trim. So we need to make sure that we eliminate any white spaces, because someone can submit like one space, and that would be considered non empty, and we don't want that behavior. So we need to trim. And if it equals an empty string, then return true. Else return return false. Simple as that. Okay, so here, what we need to do is, we need to say if is empty new user dot email, then we need to return all the errors together. So what we need to do here is we need to declare or how do we say initialize an errors object and set it to an empty object. And here, if we have an empty email, if the email is empty, we need to set a property in this errors object and say errors dot email equal, say email must not be empty. Now, if it is not empty, then we need to check whether it's a valid email. And we need to check for empty first because we don't check whether it's a valid email if it's empty anyway. So here we do else. If, and here, we're going to use another helper method. So let's create that now. And this method would be ups const is email equals, and it takes an email as an argument, and it checks whether this is a valid email. Now, we could use like a validating JavaScript library, but there's no need, we just need these two helper methods. So what I'm going to do is I'm going to paste here a regular expressions. So let's do a const. Reg x equals all of this, and I'll post this in the video description. Don't let this intimidate you. It's just a regular expression that matches for a pattern of an email. So what we will do here we'll do f email, which is this string that we pass to the function dot match, which is a function that matches a string against a regular expression. And we pass it our regular expression right here. If they do match, then we return true. That means this is a format, the string is formatted as an email, it is a valid email. And else return false. What did I do? true false, return false. Okay, cool. So here, we do else if is email, or, rather not is email. So if it is not an email, and we pass new user dot email, if it's not an email, we do errors, dot email equal must be a valid email address. Okay, so this is for the email. Now let's do the other three fields. So first one is password. So if is empty, new user dot password, dot password, then errors dot password, we can just do a line like this equals must not be empty. And let me by the way change this too just must not be empty. Because on the front end, when you have an email input that says email on it, it's not it doesn't look pretty when under the email as well, there's another error message saying email must not be empty. The user already knows that this is the email field so it's more proper to say just must not be empty. And this isn't the must not be empty. And do we do the same? We don't do the same for password for Confirm Password rather. In fact, we will just check if they are equal to each other. So what we need to do is that if a new password or new user password does not equal, new user, Confirm Password Then errors dot Confirm Password equals passwords must much all must be the same, it's up to you. Okay, the next thing is the handle. So the handle must not be empty as well. So we can just copy this and paste it and replace password with handle. And now what we need to do is that here we have this errors object, we need to make sure that this errors object is empty, that means there's no errors, that means we can proceed with the rest of the logic. Otherwise, if there is a key in this error object, that means we have an error, we should just break here and return. So we need to do is that let's do an if object with a capital O, because this is a JavaScript namespace, or class rather object dot keys, and we pass in errors. dot length, we need to make sure that the length of the array of keys is not equal is not bigger than zero. Because if it is, that means we have some errors. If it is bigger than zero, then we just return res dot status of 400 or JSON, and we pass it the errors. I think this is it. So let's actually test this. And we save and we go to postman. And here let's send just empty values like this. See what happens. Cool. We get email and password unhandled. We don't get confirmed password. But that's okay. So let's try to give it a an invalid email. thread. Let's give it a password. But no Confirm Password. Cool. must must be a valid email address for email, Confirm Password, it says passwords must match. That's actually must much password. And says, Yeah, okay, so that Confirm Password error is gone. Now let's give a valid handle. Now, Oh, I forgot to change the address. So let's give a valid email address. And now it should go through cool, it still gives us gives us another error. But this is from later on when we check whether the handle exists or not. Cool. So our validation is working. One thing you do have to note though, if we give, if we miss out on a key and not pass it, it will, it will have an internal error and not report anything back. But I'm okay with this. Because we will be the only people consuming our own API. So that so we will make sure from the React side. Because it's an HTML input, it will never send a key that is undefined or no, it will send an empty value, but it will still send that key will just send an empty value. And then we'll get the error, the proper error validation. So we shouldn't worry about that. Alright, so that's validation done for our signup route. Let's actually write the login route. So let's scroll down here. Let's do up top post. And this will be slash login. This will have as per usual, or request the response for the handler. And we need to now validate the data for for the login and the login takes two things an email and a password. So let's do const user equals and this user will have an email from the request body. Sure, can we use Never mind actually request dot body dot email. And the password is request dot body password. And here we do validation as well so that errors equals an empty object. And let's do if is empty and we pass user dot email. If it's empty then errors dot email equals must not be empty. And oops. And if copy the same thing actually. Let's select Email Ctrl D and do password and password must not be empty as to F object. Keys. Pass errors is bigger than zero oops, what am I doing length is bigger than zero, then we need to return res dot status 400. And the JSON errors. So here, if we don't have any errors whatsoever, we need to actually log in the user. So firebase.no actually dot auth dot sign in, sign in with, with email and password, and then pass those. So user dot email, and then user dot password. This returns a thing, a promise. So then data. And then we need to do the same as in the sign in as in the signup rather. And we need to return the token. So what we need to do here is the return data dot get ID token. And chain another dot then, and this will have the token. And we just do return rest dot. Jason, I don't need this to do status code. And we just put token like this. Catch, we have any error, the usual console. log, not log error, rather. Error. And res dot status 500 dot Jason. Error. Error code. Alright, so let's test this out. We save and we're still serving. So let's go to postman. Let's check which uses we have forgotten. So we have used that email Comm. So let's go here, change this to login. And what am I doing? Wrong? Yeah. What's happening? What does it look like this? Okay, so Oh, yeah. Application JSON. Email is user and password is that we hit send. And we should get a token, and we don't we get an internal server error. Why is that? Get ID token. Okay, because it's data dot user. dot get ID token? Because go back, postman sent, and we should get a token. Cool. We do. Let's test out the validation. So empty email. Yep, must not be empty and the wrong password. Oh, we should handle this, actually. So let's go here. If we have an error, let's do if error code equals this code that we just got. Then return response dot status 403. Which, which is, which means unauthorized and Jason error, actually not error, let's say, give general. And this will make sense later. Let's say wrong. credentials. Please try again. And if it's any other error, we'll just return it. So else like this. return that. And let's say but let's test it. So the same input, let's hit send. And there we go. We get wrong credentials. Please try again. Cool. So now we got the login route working and the signup route. And we have validation. Yeah, we're done for this video. So in the next one, we're going to be implementing middleware, we're going to be making sure that each time someone says because right now our send post, submit scream request, router router is not protected. So we need to make sure that whenever someone submits a post, they are actually logged in so that this route is protected. Okay, so so far in our application, we have two routes, the slash screams, which gets also the screams and the slash post, I mean post at slash scream, which both one scream. Since we have already implemented authentication, it would be nice to have some code here, that would check the authentication token that's being sent from the user to see whether this user has logged in or not. Because this should be a protected route, we don't want anyone posting screens to our database, they have to be logged in. That's one functionality. And the other functionality would be, we need to extract the user handle from that data, and then submit it into our database. So if you were to look at our database, our screens are stored, having one property inside the document saying, that's called user handle, which has the handle of the user so we can know whose screen that says. So the way this this is done is that whenever we post a request to a protected route, we need to add a header called authorization, right? Like this. And we will have a value of bearer space and then a token right here. So it would be something like this. But of course, this would be an actual token. So let's actually write code that would the code of this token or like obtain this token and get data from it, and make sure that our request is authorized. Alright, so we would actually, we could write the code right here. But since we need this functionality for multiple routes, then we need to make this into a function, and then run it, chain it before any request. So let's actually write this in a function. And the way Express works is that we can pass a second argument to, to this post, or any actually any route. And this argument would be a function that does something that intercepts the request, and then does something depending on what the request has, and then decides whether to proceed towards our handler, or to stop there and send the response, aka middleware, a piece of middleware. So let's, let's call our middleware, which we haven't created yet, if the auth for Firebase authentication, and let's create her so let's do const. So it's going to be a function const, FB auth equals, and it's going to take three things to you've already seen the request, and then the response. And the third one is called next, which is gonna, which is something that if we return it and call it as a function, it's going to proceed towards our handler right here. And we can chain as many pieces of middleware as we need. But in this case, we only need one. Okay, so here we have access to our request object, what we need to do is that we need to check if request, oops, no, not release requests, dot headers, dot authorization. So if this exists, and we need to check now we don't have to do the bearer thing. But it's a convention and in multiple frameworks and other languages, and it's a good it's a good standard good convention that everyone follows that your token has to be, has to start with the bearer space string. So what we need to do here is we need to do another check another condition, which is request dot headers, dot authorization, dot start with, which is a JavaScript function that checks that a string starts with a certain other string. And let's do bearer space. Now, if of course, as it suggests, if our string starts with bearer space, the and and it exists, then this condition is satisfied. So we'll go in here. And actually, we need to initialize a ID token variable here. So let's do a lead ID token. And then here, if these are true, that means our ID token equals request dot headers, dot authorization. Now remember, we need to extract it, we need to extract it because there's a bearer space before it. So what we need to do is, we need to do dot split, which is a JavaScript function that splits a string by a certain other string. So if we split it by bearer space, that means it's going to have an array of two, it's going to give us back an array of two strings. The first one is bearer space, and the second one would be the left, which is the token. So as to one that means we want to take the the second element, which is the token. And now that we have our token, we can proceed with our logic. But we need to do an else statement here. Because if we don't have an authorization header or it doesn't start with bearer, we need to actually stop the request here and send back an error. response. So let's do return response dot status 403 because this is an unauthorized error, let's do Jason with an error that says on, authorized. misspelled that unauthorized, cool. Okay. And let's actually console log This Just In Case console, or console error. Unless so Oh, no. token found. Alright. So here, if we pass through here, that means there is a token. So it's not enough that there is a token, we need to actually verify that this token was issued by our application and not from somewhere else. So what we need to do is that we need to do admin dot auth. And here we have a function called verify ID token. And we will pass it our ID token, ID token. And this returns a promise. So we do then. And this promise holds a decoded ID token, as you see here. So let's do decoded token. And like this. And then here, what we need to do is we need to this decode the token holds the data that is inside of our token, and which is going to be user data. So we need to add this data to our request object so that when this request proceeds forward to let's say, this route, our request here will have extra data that we've added from this middleware, and this case is going to be user data. So what we need to do is the request dot user equals decoded, decoded token. Did I misspell that? No, it's fine. Okay, so decoded token. And we also need to get the handle, because this by default doesn't have the handle because the handle is not stored in Firebase authentication system. It's stored in our collection users. So we need to actually do a database request as to return DB dot collection users. And we've also stored user ID in our users collection. So we can do where user ID equal equal equal equal. And we already have the user and the request. So we can do request dot user. And this will have a property of UID. And that's actually here, let's console log the, the decoded token just so that you see what it looks like. Okay, so now where we have this, we need to limit let's let's do a limit one, which, which does exactly that limits our results to just one document. And let's run get, and then let's train another, then we get data back. And because this is a a DB dot collection, query, and we using where, even though that we've limited it to one, this will still have a Doc's property, which is an array, and of course, it's going to have only one element. But to access it, we need to access the docs. So we need, we want to add a property to our request user. So request dot user dot handle. And let's do equals data, dot Doc's, the array, and then we take the first element dot data, the function which extracts the data from this document, dot handle, I believe we have a handle, I think, let's check in our users. Yeah, we have a handle property. So we're getting this object and then we get in this property and attaching it to our request dot user. Cool. So now here, when we got here, we need to return next as a function like this, which will allow the request to proceed towards here. So now that we have this setup, actually, let's handle the catch block. Because here if it verifies the token and the token, and it fails at verifying it, that means this token is either expired or blacklisted, or from some other issue. If it fails, it will come here. And here we catch the error. And we need to send the error, an error an error. And let's actually console error. This error and let's say error. While very fine. Oh boy, very How do you spell verifying, verifying token And we put the error like this. And let's do return response dot status. Again, a 403. And Jason error is already adjacent, so we can just do this. And then Okay, so this is done. So here, now, this means in this route, or in any other route, where we add this FB auth as a middleware, if we get here, by the, by the time we get to this block of code, we've already been verified. And we've already it's already been checked that we are authenticated. And we have access to request dot user. So what we need to do is here in user handle, we just need to do because we have this user now. So we just need to do request dot user handle, because we have we've added it to our request thing. So for our post request, we just need to send a body and that will be enough. Alright, so let's actually test if all of this is working. So we say then we do Firebase serve. Okay, let's copy this endpoint. Think I already have it on postman? Yes, I do. Let's log in to get a token. So the same data is still valid. Apparently, it's not Oh, yeah. Okay. I just needed to correct the password. Okay, we get a token. Let's now send a request to slash API slash screen. And it's still a POST request. And here, we have an authorization header. With the value bearer, let's actually test like a random value here, so that we further on purpose. And our body would have a body property of body and it says, another screen submitted, I don't know. Okay, let's send the request. And it felt the coding Firebase token fails, cool, we get this error 403 forbidden. And if we were to give the correct token, so here bearer space, this token that we got, and we send, it should be successful, cool document something, something was created successfully. And notice, we didn't even have to send the handle. And if we go to our database, in screams, and if we sort them by created at the sending. So this is the latest one. And there we go, we have the user handle user, because that's the user we use to log in with. And yeah, it's submitted and everything works. Cool. So we've already we've set up our authentication middleware. So whenever we have any protected route, we just need to add this. And there's your decoded token, it's got some token metadata, like the user ID, the expiry time, the email, and any other user extra data that you would add. So before we start to write more code, and more routes and more functionality, let's start to refactor our code and organize it so it's actually easier to maintain and to work with here, let's create a folder called utility or util. And here, let's create a file called admin dot j s. In this file, we're going to put, let's see, let's take a stick admin. So cut and paste it here. Let's take where we initialize the app. And let's take the creation of dB. And now we need these two admin in dB. We need them we need to import them in other in other files. So what we need to do is the module module, dot exports equals this admin, and dB. Alright, so next thing is we need to separate the routes for screams and the routes for users to two different files. So here in functions, I'm going to create a folder called handlers. And inside of handlers, I'm going to create a file called screams dot j s. And another one called users.js. Okay, so let's take the So here, we don't take the whole thing, we just take the handler, and I'll show you why in a second. So we just take this chunk of code, and let's go to your screams. And let's do exports dot. What was that? That was slash scream. So let's call it get all screens equals the following. Now, of course, we need dB. So we need To import that, so let's do const DB equals require. And we require that we go back one level, and then we require that file created the admin file. So utils dot admin. Alright, so here, what we need to do is that we need to do const get all screams, which is that handler function. And let's do require equals require one on the same directory slash handlers, handlers slash screams. And then here, we just give it the get all screams, function reference. And let's call, let's put a comment here and say, scream. routes. And this, there's another one here. So we take the handler, we leave the middleware. And this is post one scream, let's call it, let's call it just that post one, scream. And let's go to the screens, and do an exports don't have to worry about formatting because prettier will do that for me. So thanks, ex post, post, one screen equals all of this. And we save and it formats. I go back to index, let's copy this, or cut it, split it with the screen routes up here. What else we have? Let's forget about this for a second, we have the post signup route. So let's take all of this. It's actually a lot of code. And let's call this signup, which we haven't created yet. But we go to users. And we say exports. dot signup equals all of that. And exports now export. So here we need, what do we need? We need dB. Do we need admin? Let's search for admin. We don't need admin. Let's remove this to do because we've already done that. And let's bring in dB. So const dB, Rick, because require, go back to one level and do slash detail slash admin. One thing one other thing we need here, I think is Firebase. Yeah, we need Firebase. So we can do here five days, or construct a const. Firebase equals require the package Firebase and Firebase, let's initialize it. So Firebase dot initialize up, we pass it config. And it's good practice to put the config file separately. So let's do const config equals require. We haven't created this yet, but we will in a moment. So we go back one level, and we go into util. And we do config like this. Let's create that. So here we do config dot j s. Oops, what did I do? No, not conflict slash j s. Let's delete that. Or let me delete that you probably didn't make this mistake. So config dot j s. Let's go to the index. Let's grab this. So go to config and we do module dot exports equals this. And, okay, so what's next? Okay, let's bring in the signup handler. So const. Sign up. Let's do login as well, which we haven't created. But we will, because require handlers slash users. Okay, so let's take the login handler as correct and right login instead of it. Let's do this. Let's go to users. Still exports got login, equals all of that. And we need Firebase we've already instantiated or initialized rather Firebase. Do we need admin? We don't. Okay. So in the index, now we have these helper methods. Let's take these routes, let's put them let's put them here. Let's call these users routes. And let's take this off middleware Ops, pay, copy all of it. Now let's create a new file called FB auth dot j s and you Let us do module dot exports equals equals all of that equals all of this. And what does it need it needs admin. So we need to import that const admin equals require admin, which is in the same directory. Okay, so let's take these two helper methods, or functions. And let's create a validation file or validators, validators dot j s. And let's have these two functions here for now. Let's go to screams. Not screams users. So let's take this validation from here. Let's copy all of this. Okay, let's see how we can do this. Let's copy all this. So this is for the signup route. So let's create a function exports dot let's say validate, sign up, like signup like this signup data equals, it's a function that takes data and does the following. So we have errors. And here instead of new user, we just say data. Wherever there is a new user, we put data. And the thing is we don't return status or anything from here. We will return errors. But let's also return another key with errors. So let's do what do we do? Let's do return error errors. And along with errors, we return another Boolean called valid. and the value of this is this. Actually, let's compare it to zero. So if we have zero then or do we actually need to put the ternary operator? Actually, let's do because it might be a different data type. So So if it's if there is no keys, it's true. Otherwise, it's false. Because if there's no keys again, in errors, that means there's no error, that means the data is valid. So we return this object that contains the property valid. And if it's the property valid is true, that means the data is valid, then we should carry on with whatever that's happening in that function. Or in that handler. Okay, so I think everything is okay here. So we need to import this. So we go back to users. And let's do right here. Let's do const, validate signup, data equals require. And we go back one level, and we go to util slash validators. And let's do as well, validate. Do we need to validate login data? Yeah, yeah, by the login data, which we haven't created yet. So here, in the signup, we'll do const valid. So we this is called destructuring. Because we're going to extract valid and errors from validate signup. Like this. Yeah, it's like this sign up. Data. Why is it not? suggested I misspell something here. I did. Okay. Oh, actually, wait, sign lots sign like this. Yep, sign up data. And we pass new user. And let's correct that because here we call it like something wrong. So sign like this, or I called it. Let's create also. Okay, so here, we need the conditional, so if not valid, then we return result dot Jason, or that status first. of 400. Got Jason. We passed the earth. Otherwise, we just carry on. So let's do the same thing. Let's copy these two lines here. Let's go to login. And here we do like this. But instead of sign up, we say login. And we pass user, not new user. And everything is fine here. Let's copy this logic here. And make it into a function and validators. And the fun shall be called exports dot function will be called validate login data. And it will take data and it will do the following errors. Let's do the same thing here. So return errors and valid. Okay, so did we also in the index we need to import the auth middleware authentication middleware. So const FB auth equals require you to slash util slash FB off like this. Let's save everything. Let's see if it works. Firebase. So let's see if I didn't mess up anything. Okay. config is not defined index. config. Oh, we don't need to initialize Firebase here. Excuse my dog. Okay, we need to bring post one scream actually. Let's try again. One more time. All right, let's copy the URL. And let's go to postman. Let's try to fetch all the scripts. So get through the authorization header, even though it doesn't matter. Okay, fetches all the screens. And we tried to go to sign up. And it's a POST request to give a body. And here let's give it an email. Give it like something wrong. SATs. Password 123456. Let's give a Confirm Password. The same? Actually, let's try the validation. See if it's linked properly. So handle let's say new. Let's send. Cool. Okay, so let's give a valid email. So new at email calm. And the handle is new. And we give same password we hit son. Cool, and it works. So as you can see, now our code is looking so much better, like the index file is so minimal. And everything is now separated into their respective files. So now this will make it so much easier for us to work on our routes. And we know where to go if any error happens. So now that we have our handlers for our route for screens and users in two different files, who can actually start to add more routes to further enrich the functionality or up Alright, so before we do anything, I want to like fix two things that I they forgot to fix. So here in the auth middleware, we need to actually import DB because we need it right here to access our database. And in validators here, when validating user data, we don't check for user email, we check for data, because that's the name of the argument. Cool. Alright, so the thing that I want to work on this video is setting a route for users to upload the profile image to so let's do that. Alright, let's create a route here. And the users route is going to be a post route. So slash app dot post is going to post to slash user slash image. And the function is going to be called upload, upload image. And let's import that from our not from users. So upload image Let's actually create that let's save this and close, close this, save this and close this. Well, let's go to users. And here at the bottom of users, let's create this function exports dot upload. Image equals, it's going to take a request response and an error function and it's going to do something. Alright, so for this, we're going to need the package called, well, there's multiple packages that do this, but that we're going to install something called busboy so and make sure that you're in functions, and run npm install, dash dash save bus, boy. Alright, so if we look at the documentation for bus Boy, you just install it, and you in your function, ignore this HTTP thing because we're already in a handler in your function, you run this on event on file, and then you handle the file upload, and then you run on finish. And then you stop the process. And you upload your image using whatever library that you're using. In our case, it's Firebase, or the Admin SDK. Alright, so let's do const. busboy equals require bus, boy. Let's bring in a couple of other things. So const path equals on path is a default package that's installed on any node. Node project, spring, another default package called OS. So OS equals require OS. Another one, it's Fs. Triple D stands for file system. Alright, that's all the imports. Let's instantiate an instant instance of busboy color. busboy equals new bus, boy. And this takes an options object mainly had his item in it, and this is going to be we're going to give it the our headers that we got in our request. So request dot headers. And here, let's do our own file event. So busboy.on, and the event name is called file for file uploads, and the handler is going to take a couple of things. So first one is field name. And as you see here, second is file. Third is file name. Fourth is encoding. And fifth is MIME type. Now, and don't be overwhelmed by this, we don't need all of these, we just knew the file name, your file name, and MIME type. But even though that we don't need encoding, for example, we can just do this because otherwise MIME type will have the value of encoding because it's the fourth argument in the handler or in the callback function. So here, we need to get the extension of our file or of our image file. So let's do const. Image extension. Extension. Yes, public correctly equals, now let me show you how we're going to extract this. Let's say we have an image file called image dot png, or not orangey. png, we need to get this PNG or if it's a JPEG, we need to get the JPEG. What we can do is, we can, the problem is we can have an image called for example, my dot image dot png. So what we need to do is we need to split this string by dots on each.so. Let's do is a file name, your file name, dot split. And we pass this a string and not a string, a dot. And here we have an array of strings or strings. So we're going to have an array that we'll have for example, in this case, it's going to have the first value is my second image. And third is PNG. So we need to access the last one. So here, this is an array, so we need to access the last item, which is going to be file name dot split by dot again, dot length minus one. All right, so here, this is gonna give us the index of the last item. And then this will give us the value of that which is going to be either PNG or JPEG or whatever. So here we need the actual image file name. So let's actually actually create one so const or we call it image or image file name. And let's just give it like a random value. So math dot random times, times, I don't know 10,000 billion. Actually, we need to run Under this to get rid of the decimals, so math dot round surround all in math dot round, like this. And we need to concatenate a dot and concatenate the extension. So let's make this into a template literal string. And make this into a variable like this with dollar sign curly braces, let's add a dot and do another dollar sign curly braces and add the image extension. So an example of this would be like this. So it could be like some random numbers dot png. Alright, so let's close the template string. And let's do a semi colon. And now we need to get the file path. So let's do const file path equals path, dot join, join. And here we need the OS namespace, OS dot temp there for temporary directory, because this is not an actual server, but and, but a cloud function. So let's do image. We can catenate image file name that we just created. And then here, we'll create a way actually, what am I doing? Yeah, we're gonna need image file name and this object that we're going to create later. So let's actually declare them, we're going to need them in a different scope. So let's declare them here. So let's do let image file name. And we're going to need something else called image. Give it a more expressive name. So image to be uploaded. and initiate, initialize it as an empty object. So here, we need to actually create this image to be uploaded. So image to be uploaded. It's an object and it's going to have two properties, the file path with the value of file path, so we can do it like this. And the MIME type. Let's console log this, so that you see what these values actually hold. It's useful to sometimes do it. So field name, we don't need file because it's a weird to where doctor console dot log, file name. And console dot log mimetype. All right, we don't need the rest, we just want to see these values. Okay, so now that our file is created. Now, I mean, our object is created, we need to use the file system library to actually create this file. So let's do file dot pipe, which is a no j s method. And we pass it Fs dot create, write, stream stream. And inside of the stream, we give it our file path that we created. And now this is going to create the file. Now after this event is due busboy.on. And this event is the finish events. Once this is done, this will be executed, it's going to have a callback that doesn't take any argument. And here, we need to upload this file that we just created. So admin, that, Oh, we don't have admin, we need to bring admin in. So here we bring admin, let's go back down. So here we do admin, dot storage. dot bucket, dot upload. And this takes a file path or a path string called here, which is going to be image to be uploaded that file path. And the second parameter or argument is an options object. And there are a couple of options, but we just need resumable resumable. And we give this value of false. And we need an object for metadata, which holds and by the way, this stuff is in the Firebase Admin SDK. documentation for now, I really suggest you look at that because it helps understand what what the hell we're doing. So this metadata holds another object called metadata. And we're gonna have a key called content type that I'm spelled correctly I did and this will have the image to be uploaded, dot MIME type. Alright, so this upload function returns a promise. So we change then and I believe we don't need anything from that. Yeah, so we just go like this arrow. And here, what we need to do is we need to construct the image URL to add to our user. So actually, yeah, yeah, we need to do const. image URL equals, and this will be template string, HTTPS, colon slash slash. Was it for Firebase Storage dot Google. Google API's dot com, slash v zero. And I'll show you in a second how I know that this is a thing, slash v zero slash b slash dollar sign, curly braces to put here, what we need to put is forgot to the conflict file, find that we have a storage bucket key. So we need this. So we need to do we already imported it in this file. So we need to do config dot Storage bucket. And we need to keep on going so slash Oh slash, here, we need the image URL that we just created. Now, we need to know we need the image file name. So image, file name. And this is why we created both of these outside of this scope so that we can access them here. Okay, so image filename, and we. This is not actually we need to chain alt, this URL parameter alt media, alt equals media. Because if we don't, whenever we access this URL, without the ultimate idea, it's just going to download the file to our computer instead of showing it on the browser by adding this alt media actually shows it on the browser. Alright, so this is the image URL we need to do now is we need to add this image URL to our users use a document which is right here. So let's go to our database. Our user here needs to have a key called image URL, and we'll have this value. And so here, what we need to do is we need to do return Doc not.db dot doc, and this document would have so template string, you the path for this document is slash users. So in the users collection, slash dollar sign, don't forget that this is a protected route, if we go to admin, and non admin index. So in the index, I actually made a mistake here. So this is a protected route, we need to add our auth middleware authentication, middleware FB auth, because this is we can't have anyone upload an image to our server, or to our storage bucket. So we add the middleware here. And because we've added the middleware, this gives us access to the request dot user, because when we reach here, that means this has been authenticated. And we have that user object. So here, we do request dot user dot handle, which will let us access the document of this user. And instead of running get we run update, so dot update, an update takes an object and in each object, you can do field and give it a value, and it will update update that field with that value. So here, we need to update the field called image URL. And of course, if it doesn't exist, it's going to create it, that's going to have the value of image URL that we just created here. So we can actually just get rid of this and put it like this. Cool, this returns a promise we already put return was changed, then what does this have the right result, that's useless. So just don't take it away, just go here. And here, we just return res dot Jason. And it's going to have a message, this doesn't matter, really. And let's say image uploaded, successfully. Cool. And of course, here, we handle the error case. So catch error, console, dot error, error. And then we return res dot status 500. And with a Jason with an error, error code. Alright, one thing I forgot to do, actually, is that whenever a user signs up, by default, they should have whoops, here. No, not postman here. So I click on postman again. I didn't actually that was a bug. Okay. So whenever a user signs up, we need to add an image URL right here that will have a an image that has like no face. I mean, this I don't know. How to describe this this thing I've already downloaded, I'll put the link in description. So we want by default, whenever someone signs up, we give them this image. And until they upload a new image for themselves, they have this when they upload a new one, they will have the new one. So let's actually manually upload this to our bucket. So we go to storage. I think for you, you have a blue button here says activate storage, I've already done that. And that's up upload this file. And the no image file, I called it no dash image dot png, I'll tell you why matters what I called it. So it's right here, it's in our bucket. Now what we need to do is go back to our code. And here whenever someone signs up, let's give them this image. So after the validation, let's do const image, or no image equals that name. So no dash image dot png. And here when we create the entry in the users table, we are the key news is document. Then why keep saying table? Because of SQL. Okay, so image URL, and the image URL would be the same thing that we had we had here. Whereas this thing, so let's copy all of this. Let's go back up. Where are we? So right here, Storage bucket, but instead of image file name, it's gonna be no IMG. All right. And that's the comma. Alright, let's test all of this. It should be working. So yeah, let's save everything. And let's run Firebase serve. Not save serve Firebase serve. Let's sign a new user up. Okay, so this sign up. And here we have given new@gmail.com password of that password. The same thing? And, or not password? Confirm Password. And here we'll have a handle new. And let's send this email is already in use. Is it? Clear? Let's do another one. So new to handle is new to cool get a token. That means we've signed up successfully and go to authentication we have new to we go to database. And in that user new to There we go. We have the image URL, and it's the images the no image. And if we copy that, and we access it out, we get four or three error. And why's that? Oh, okay, I know why. It's because we in the storage in the database access rules. By default, it doesn't allow anything and unless we're authenticated. But we're not using the client library, we're checking the authentication through Cloud Functions. What we can do here we can do allow, read. So this by default will not allow right we will only allow read, which is not a problem for us, because all the files that we're storing here are just use a profile images, which are public anyway. So let's do allow read publish, as published. Now, if we refresh, there we go. We see that image. Cool. So now by default, our users have this no user image. So let's actually test if uploading a new image works. So we have this user new two, they have this new image. Let's log in as new two. So remove these two things and change this login. Actually, we could just use this token, it's the same as take this token. And on the same route, let's go to I mean, on the same tab, let's go to slash user slash image, it's going to be a POST request. And it's going to have the header also realization there. And we paste that token. And here instead of a raw body, we give a form data type body. And this key Let's name it image doesn't matter. But let's name it image. And here. Yeah, let's change the type from text to file. And let's select the file and let's select this user dot jpg. And let's send let's see if it's actually uploaded successfully. keeps going forever. Oh, okay. I know why. Whoops. All right. So here at the end, where am I? Okay, we're here. So after this unfinished event, we need to add busboy that and and we pass this request to row body, which is a property that's in every record. object. Let's save and it runs again. And let's send the same request. And it says image uploaded successfully status code 200. Cool. Let's go to our new two. And there we go, we have a new image with a random name if we go to storage. And by the way, when you click on storage, you go here, file location, and you take this download URL. And you go here, it gives you a URL with a token and an access token, which you need if you don't have access permission. And if you just remove that you hit enter, there we go, we get that image. And the same URL is stored is stored in the database in the user's document. So which one is new to, and there we go with that URL, we copy it, we paste it, and it's exactly the same image. Cool. And if we try to upload another image, let's upload this PNG, sand. And it's uploaded. Someone called this image young men instead of young man. Nice English. Alright, so we copy that, we go here, and we see the young man. Alright. So the image upload is working successfully. But there is a catch here. So let's say I already created this, how convenient. So let's say we have a text file called hello world. And for some reason, it takes ages to open a text file, and it's got the value hello world, we can actually upload this file instead of an image, text and we upload it as uploaded successfully. And it's actually assigned to our user image, a text file. And if you don't believe me, if we paste it, we get hello world. That's not very good. So what we need to do we need to handle that here. And by the way, these are the prints we're printing. What are we printing? What is this? Oh, this is the decoded token. Let's actually remove that. Let's go to FB auth. And remove this print or this console log, we save. So if you as you can see here, we're actually logged in the after the token will login the the the name of the field, and the name of the file and the MIME type. So when we uploaded the text, the MIME type was text slash plain. And when we uploaded the PNG was image dot png, PNG and the JPG is exactly that. What we need to do here we need to, if the file type is not PNG, or jpg, we don't want to allow our users to upload GIFs or text files or whatever. So we need to do here. Let's do F, MIME type does not equal image slash jpg. And MIME type does not equal image, oops, image slash PNG, then here we just return an error, return res dot jpg, not just give a status code of 400, bad request dot JSON with an error message that says wrong. file type submitted. Let's test if that's working, we save then we go to postman with the same text file, we send. Call, we get wrong type, file, file type, whatever. And then if we submit the user dot jpg, it actually uploads and it changes in our database that it changes to a JPEG. Cool, so that's image upload. I know this has been a long video, but yeah, it's it's a little bit complex to handle image upload. In this video, we're gonna work on adding user details. I don't know if I've written this in a past video, but you can take a time to write or read this. So this is our basic user basic user info. And these are extra credentials that we could use through that we could add through our front end, a bio, a website and a location. And of course, they're optional. So let's write a function to actually add these details. Let's go to our index file, create a route for this. And this will be a post route. So I've got a post. And this will point at slash user. And this will, of course be a protected route. So let's add the middleware FB auth. And the function will be Add User details, which we haven't created yet. But we will in a moment. So let's import user details. So let's go to users save this and go to users. And here Actually, I'm going to put it above the upload image. Let's put a comment here. Add User details and exports dot add User details, request response as per usual arrow function, let's actually put a comment on this as well upload an image, a profile, not an a profile image for user. Comment here as well log us in. Now, I'm not writing a lot of comments, because that could take up some unnecessary time you feel free to write comments as you go. But I believe in if you write expressive code, and you name your variables properly, whenever you write clean code, you feel like you don't need to comment as much. But of course, sometimes commenting can be useful for other people to read your code. Okay, so let's actually write this function. So here, we need to take a couple of details. And the thing is, I'm going to write right now not a validation method or function, but it's, it's a function that will take the input and make sure let's let me actually write something and then I'll explain so let say, let us details. The details equals, we're gonna write a name of a function that I haven't created yet reduce user details. And this will take in the request body. And, whoops, what did I do? Okay, semicolon right there. And let's bring in this request, reduce. Reduce user details from validators, let's go there and create it. So and validators at the bottom here, let's do export dot reduce user details, it will take data. And here, like we mentioned earlier, we need, we're gonna take three things a bio, a website, and a location. So as to let user details, initiate this as an empty object. And here, we're going to do one check, actually, a couple of checks here, if not, is empty. And we take in the property data. Remember that this data is request dot body. So in body, we have our properties bio, that is the first one so data dot bio, of course, dot trim, to remove any whitespace. So if it's if it's not empty, then user details, dot bio, equal equals data dot bio. If it's empty, then this will not have a bio property. So here we list do If not, is empty data dot website, dot trim. Now here, I'm gonna do something like this tiny, clever trick, where what I want to do is that if a user submits a website like this with HTTPS, or HTTP at the start, so website.com, we're going to save it as it is. But if they don't, if they just submit website, comm, we want to add HTTP, colon slash slash, and make sure that HTTP not HTTPS, because if a website doesn't have SSL, it will actually crash or not load anything if you do HTTPS, but a website that does it will still allow us to use the protocol, protocol HTTP and we can still access it. So let's do If not, we've already done our if there is not if here, so user. Oops, user details. The website. Yeah, the website, actually doing it another. Yeah. Whoops, we need to check for the HTTP. So let's do if data dot website, dot trim again, dot substring. Actually, the S is miniscule. So substring, all lowercase. And here what we're going to do substring, it takes a substring from a string, and you give it a start and an end. So the start would be zero, and the end will be four. And actually, this is not a four here is actually the P for some reason, and it's not s you would think that four would be in HTTPS, four would be s but apparently it's not this, this function behaves in a weird manner. So if we compare this substring to HTTP, and then so if this is true, that means the website already has no actually this is what Compare it, we're making sure that it's not actually to be if it's not HTTP. That means we need to add that to the to the website. So let's do user details, dot. Now you don't have to do this, but I think it makes it makes it more neat. So we add HTTP, colon slash, slash. And then remember, this is a backticks. And then dollar sign curly braces, data dot website, dot trim. All right. Now else, else, this means it has HTTP already, we just actually, we don't need curly braces, we can just say else user details, that website equals data website. Now for the location, it's oops, not here. So for the location, we just say, if we're gonna do the same thing as the bio, nothing fancy. If replaced bio here with bio, so location. What, why we're doing this is that with our front end is definitely gonna send three properties by a website or location, even though if a user doesn't send a bio, if they leave it empty, our, our react app is going to send a bio property with an empty string. So our code here makes sure that we don't actually submit a an empty string for a value of a property to our database. If it's an empty string, we don't even add that key. So here, we just do return user details. And this function is done. So let's save and go back to our users file. And we've brought that in. So where are we we're here? is odd us? Oh, boy. Okay, we're here. Sorry about that. Okay, so here, what we're gonna do is, we're just gonna look for the document of this user. So let's do const user document. What do we do the document? Yeah, we're actually going to need just actually we just do.db Doc, and backticks slash users. Remember, this is a protected route. So we have access to the to the users object. So request our user handle dot get, sorry, not get the update. And here, it's actually as simple as just passing this user details. Because this user details will have, let's say, if it has bio on a value, this will just update exactly that. So it actually works out to have an object shape like that. So here, the update returns a promise. So then, and here, we just return a message. So let's do return res dot JSON. And the message will say, details did successfully. And catch we have an error, which is console dot error, error. And we return it return res dot status 500 dot Jason error code. All right, I think this is it for this function. So let's save and test it. Let's make make sure we we saved all files. And I've already got Firebase running. So if we go to postman, and here change this route to just slash user, as opposed at slash user, and yeah, I'll send and Okay, my token has expired. it expires after an hour, so we need to log in again and get a new token. So let's login. Let's copy that token. let's paste it here. Okay, I'll just type again, space token. Let's send this Oh, actually, I need the body. What am I doing? Yeah, yeah, the thing is like the other vital the validation as well, we have to have our keys. And of course, our front end is going to make sure that we have our keys. So let's do actually an empty bio. to test whether it's not submitting an empty key to the database. To do a website. Let's call this user.com to test whether it's going to add HTTP to it. And let's do a location of London, UK. And that sound cool. It says details added successfully. Let's check our database. So go to our app database. Go to our user, which is user right here. Cool, we have a location. And we have a website and it's other HTTP two. And we don't have a bio, because it's empty. Let's try to override these details. Let's say, my bio now says, Hello, I use a whatever. And I changed the website to google.com. For some reason, I'm the owner of Google Now. And I moved to Los Angeles, California, because why not? Let's send details added successfully. Go to the database. And there we go. We have the new details. google.com la, California, and, and yeah, Hello, I'm user, we have the bio now. Okay, cool. And if we actually add the HTTP to HTTPS, colon slash slash google.com, and we send There we go. So HTTPS, so it doesn't alter it right now. All right. So next thing, let's actually work this other route, because the way our application is going to work is that we keep the login route minimal to reduce response time. So that when we log in, we only get a token. And then when we're redirected or directed to the homepage, we use that token, and we send the request to a different route to get all the details for our user. gonna copy something, just to not waste time writing it from a different file. And I'm going to paste it actually, I'm just gonna copy a part of it. User details, and I'll explain it in a second. So let's close this object here. So this is going to be our Redux data. This is going to be what user information that we're going to hold in our Redux state in our front end application. And we will use to populate our profile with, we need credentials to show them on our profile on the right. And we need likes to actually check on the homepage or on any page, whether any of the posts that are listed there are liked by us, and to like show a different icon. If they are, if they're not, we just show the empty heart icon. Alright, so we need to write the router that actually returns this data for us. And this data will have more later when we implement notifications. But for now, we're just going to get credentials and likes, you can take your time to write this if you want. Alright, so let's go to index and create this route. And it's going to be an app dot get slash user as well, it's going to be protected, because we're going to use that token to get the data. And it's going to be called get authenticated. user or just get authenticated user. The names don't really matter, as long as they make sense to you, and you can remember them it's fine. Alright, so let's import that. And let's go and create it. So in users here underneath our user details, put a comment, get own user details. And let's do exports dot get often dedicated user equals request response arrow function. And here, we need to, first of all, let's declare a let rest data. Because empty object This is the response data, we're gonna start adding data to it as we go through our promise chain. So first thing we need to get the user so DB dot doc, slash users slash dollar sign curly brace again, request dot user dot handle dot get dot then. So here we're gonna get a one document. So Doc, our function, we're gonna do a check if the document exists, just in case because if you don't do this check is going to crash. So Doc, if doc dot exists, if it exists, then user data, actually, is it user data? response data? Yeah, rest data. It can be a user data, let's change it actually, to user data. It makes more sense. Now that I thought of it like that, off the top of my head, it does make sense. Okay, so user data credentials. Equals as simple as doc dot data. And don't, don't forget that this is a function. So don't take and do curly parentheses. So here, Let's now get the screams of this user. Actually, we don't need the screens, we just need to get the likes which don't exist right now. Okay, let's do that. I don't know if it's gonna crash the app if it doesn't exist, but let's try. It never hurts to try something. So DB dot collection likes where use a handle. We haven't even created this collection yet. But let's roll with it equals request dot user dot handle. And we're not gonna order this by anything because they don't have a created a created art. So it's just do don't get then we get data. I'm here, we need to look through this data. So let's do data dot for each document. We need to actually initialize user data.so as to use the data because if we don't, it's going to crash because it doesn't know it's gonna mess up with types. So it's actually not user data user data dot likes equals an empty array. And here for each document, we're going to do use it data likes dot push, document that data like this. And then when it's done, we just return the data. So when it's done here, we do return response, or stress dot JSON. And we pass user data like this. So of course, here, catch her the usual console, error, or return rest dot status 500. Jason code. All right, let's test if this is working. Let's go to postman. Make sure you saved all your files. And here with the same token, we're gonna send the get request and put the body as non because it's a get request with the token, and let's hit sand. Cool, we got credentials, and we get an empty likes array. And even though the the collection doesn't exist yet, it returns an empty array. This is how Firebase works based on document references, it will still have a document, and it will still have a reference even though the document doesn't exist, or the collection in this case doesn't exist. Cool. So we have credentials. So we have now a route to get user credentials. Alright, so far, we only have two routes for screens, one that gets all the screens, and one that posts a screen. Let's add a route for getting one screen and getting all the details that are pertaining to that one screen. Alright, first of all, like these three user routes should be grouped with the user routes like this. And let me remove this whitespace. Let's, let's write this route. So this will be a post, of course. So up, sorry, get get at slash. So this, this is the URL that would need the scream ID that we need to because this is the only way of sending data through a get request is in the URL parameters. So we'll do a slash screen slash colon slash scream ID, this colon will tell our application that this is a route parameter. And we can access its value. And of course, it's not protected because we want in our application to allow users to view screams and comments and all this stuff, even when they're not logged in like Twitter, because this is kind of a Twitter clone. Alright, so the function will be called get scream. And let's actually, I want to write all the other routes as a to do so that I'll so that you have an idea of what we're going to actually be creating later. So we're going to have a route for deleting, so delete screen, and we're going to have to do let me copy this to do so that I have to type it again. Like a scream oops, scream and we're gonna have another one for unliking a screen We're gonna have a comment on screen. And I believe this is what we're gonna do next, because it's the one that makes sense the most. All right, so we have a route for getting one screen. But before we do that, I want to add some dummy data on Add a collection, a comments collection, which holds exactly that. And before I add the document, I want to copy something and paste it, I don't want to type it and waste time on it, because you might not want to type it, I'm going to paste it right here. So these are the, our comments are stored in our database. So they have a user handles so that we will know who submitted this comment. And they have a scream ID. And that refers to which screen they pertain to. So when we grab a screen, we grab it's comments by this scream ID property. And they have a body of what the comment says. And of course, they have created add on of one they were actually created. Alright, I believe maybe later, they will hold an image URL as well of their user. But but we'll see, I'm not sure yet. Alright, so let's create a comment like this. So what we need is for things a user handle a scream, ID, a body and a created that. So a scream, Id will get from this one screen, so copy this. And then let's create the collection. Again, it's gonna have an auto ID a field of scream ID, that scream ID a user a handle. We only have one user right now, or at least because I deleted the other users a body which will say nice scream, man, exclamation marks, or ape, I suppose makes more sense. And a creator that which will be a string. And let me copy this date. From here, cool. Alright, so save. There we go, we have a comment that is attached to the screen. I mean, it's not attached, because this is a document based collection, but we will make it so. So let's go to our screens. Actually, let's go back to index, we need to import this, copy this get screen and add it to here. And let's save all files, go to screens dot j s and let's create this get screen function. So exports dot get screen. Equals takes a request the response are a function to let's declare a variable scream data. It's an empty object. Let's do DB dot document doc and the back backticks and do slash screams slash dollar sign curly braces to access a variable request dot params. four parameters dot scream Id like this. Get, of course this returns a promise. And this will hold the document. So let's do let's do another check as well. So let's do if not doc dot exists, which is a Boolean that that tells us whether this document exists or not. We'll hear stop and return res dot status of 404, which stands for not found JSON with an error of the scream, not found in case someone sends a request to slash scream slash an ID that doesn't exist anymore. All right, so else we just add this data. Well, we don't need to do an else because it's inferred already. So let's do screen data equals document dot data as a function. And then now we want to add the ID of the screen to the data because we're going to need that later. So let's do screen data dot scream ID equals doc.id. All right, so now we need to fetch the comments of this screen as well. So let's do return DB dot collection. Calm comments where scream ID equals request dot params dot scream ID dot get. So this returns a promise. So we do another one here then and we get a query snapshot because this one Won't be this can be multiple documents. So let's initialize a safe scream data dot comments equals an empty array. And let's do data dot for each document. Allow us to scream data dot push, and we push doc dot data. And we don't need the IDs of the comments. So after here, so our comments are already there. So we just need to return the data. So let's do return. scream. No, not not scream data res dot Jason. No without curly braces just scream data like this because it's already adjacent. And of course, catch and response dot status 500 dot Jason. Code. All right, I think this is it for this function. Alright, let's test if this is working. So I'm already running Firebase serve. If you're not take the time to run it. And let's go to postman and test this up. Okay, so this is going to be slash scream, slash a scream ID. And let's go to our database and grab this scream ID right here. Paste it. And it's a get request with no headers. Even though if you have headers, it doesn't affect it, sort of just send it and loading. internal server error, interesting. Scream data dot push is not a function. Oh, it's because scream data dot comments. dot push, oops, as comments is the array of scream data is an object. All right, let's try again. Cool, we get our data. And what we need to do though, because right now we have only one comment. So it this problem doesn't appear. But if we'd have multiple comments right here, it's going to sort them differently. Actually, I'm not sure what it sorts them by. But we needed to sort them by created that because we want to show the latest one first. So let's go here. Let me close the console. And here after we fetch our comments, after the collection thing, and we say order, like this order. How do you spell order by by created art, and in a descending order. So let's save and run the query again. Well, of course, we're not going to see any difference because it's just one comment. And we get an internal server error. Oh, I know why. It's because Firebase, when you have a five complex Firebase query, you need to create an index for it. But usually it gives us a URL. But some for some reason, this URL is formatted in a very funny way. Let's try again and see if if the the response like the console log is actually formatted properly here. Alright, so this is the URL you're going to get as well, the URL, it says it's going to say the query requires an index, you can create it here. So you just collect this Ctrl Click from the console, so that opens it on the browser. And what's cool about Firebase, the index is already ready for us to be created. However, this doesn't show anything for some reason. Let's go to index this again. Okay. Let's copy and paste this. All right, we'll click Create index. And this is gonna take a couple of minutes so I'll be back on system. Okay, now that our index has been created, we can actually send this request again and it should show us the data And it does. And now even if we add another comment, actually, let's add another comment just to show that it works. So let's go to our comments. And let's do oops, no other comment. And what fields Do we have, we have a user handle the same user, and we have a body, say another comment. And we have a creator that may copy that date from that file, right here. And we're going to add one day, instead of the 15th of March, it's going to be the 16th of March. And we're going to have another field of scream ID. I'm going to copy it from here. And submit that and send the query again, we get two comments. And the latest one is this one, we get it first. Cool. All right. So let's create a route for actually submitting comments without having to create them on Firebase manually. So let's go to index instead of this to do comment to let's do app dot post, add slash scream, slash screw, colon, scream ID, screen ID slash comment. And this will be a protected route. So let's add the auth middleware. And this will say comment, on scream scopic comment on scream, let's go to here. And let's go and create it. So here at the bottom of the comment here saying, Our get or fetch, fetch one scream. Fetch makes it makes it sound like like the code is my, you know? Like, the code works for me, which makes more sense, because it does. Alright, exports, I don't know, comment on screen equals request response. And here, what we need to do is we need to validate the body, but we only have one field, so we don't create a function for it, we just say request dot F request dot body, dot body again, because the property is called body dot trim the equals an empty string. That means the user sent empty data. So let's do on the same line return res dot status 400 with a JSON error, I say, comment must not be empty. Or actually it just must not be empty, because the input will already say comment on it. So if we say comment, again, doesn't make sense. Otherwise, I'll do const. Let's create this comment object that we're going to persist to our database. New comment equals object. The body of the comment is request apps request dot body dot body. The created art is a new date, to ISO string. The screen ID is request dot params dot scream ID, the user handle we get from our request dot user object that's passed through our middleware. So the handle of course. And actually, we do need to store the user image. Because what we want to do later when we fetch the comments, we don't want to fetch the comments. And then depending on that comment, as well fetch, depending on the user handle of the comment as well fetch the profile image of the user. So let's do here user image, add something called user image. And this will be request dot user dot image URL. Now, we haven't added this yet, but we can. So let's go to our util. What's cool about this because we've already sent a request to the database. So we already have all the properties of the user. so here we can just add another one called request dot Use a dot image URL equals data dot Doc's zero dot data the function dot image URL. All right? Yeah, we're done here. Let's go back. So here we have the user image stored with the comment. So let's persist this. What do we do actually? Oh, we need to actually confirm that the scream exists because this screen might not exist anymore. So let's do DB dot doc backticks slash screams, slash dollar sign thing. curly braces, request dot params dot scream ID to get this screen dot get, then Doc, because this is DB dot doc, so it has to return one document. So let's say if not, dot dot exists. So if it doesn't exist, we return res dot status 404. Because we don't want users submitting comments to ideas that don't exist anymore, and then we will have to like persist comments with scream ideas that don't exist anymore. So we just say here, if the scrim doesn't exist, we say, screaming not found. And then if we pass this, if and nothing happens, not not pass it as in if it's not triggered, then we just do DB dot collection. And it will be the collection of comments. Now we add our comments. So dot add, which I believe we haven't used yet is this is the function that you use to add a document and you pass it a Jason. And in this case, our Jason is already created. So we copy that and we add our new comment object. And here we do dot then this returns a result, I think, not actually a document reference, but we don't need it anyway. If we come to this done blog, that means the document was created successfully. So we just say rez, you actually need to return it res dot Jason new comment, we return our comment back to the user, because they need to add it on the user interface. Because here we do catch error. And console dot log. rows, rez not released event res dot status 500 JSON error code or oops, actually, what am I doing? This could happen a lot. So we could just say error. Just say something, the classic something went wrong. Okay, so let's save all files. And now let's go to postman. So we have this scream ID we do slash scream slash scream ID slash comment. And before we do that, we need to actually log in. Let's copy all of this, open a new tab, send a POST request with the body of type application Jason. And let's login. So email will be user@gmail.com or whatever user you have on your database. password will be the password we set for we set for it. What 404 not found, oh, oops slash login. Let's get the token. So here, still bearer token. And by the way that a request we did earlier to get the screen was not protected one just to prove to you. Let's send a get request without the authorization header. We still get the screen because it's not protected. So here slash comment, and we put the token and in the body we have if you remember we have only one property of body. And this will be comment. Number three. Let's send or not get post. Send. Scream not font. Really. It makes sure I got the right ID Did scream not found? Oh, what am I doing scream ID not screams. Okay, let's try again. Something went wrong. Let's check the error log. line number 96 return DB dot collection. Comment, add. You comment? What's wrong with that? Okay, so after console login, the comment that object I created, turned out that the user image was undefined for me, you probably didn't have this error. Because the because when I log signed up this user, I hadn't implemented the image URL logic at that time. So let's just add image URL here. Or let me just add this and add the link to the new image. And this should fix the problem. Yeah, okay. So now image URL should would not be undefined call. Because when I was trying that one, one of the keys, we had the undefined value, which is not allowed by Firebase. All right, so the comment is submitted now, and I get the comment back with the user image, which we'll use to display on the comment and the front end. And if we go to our comments collection, we see that we get comment number three cool with the user image. We're going to create two routes, one for likeness cream, and one for unlikeness. Cream. So we got app dot post, or is it post, actually, it can be a get request to opt out, get slash scream, slash, colon scream, ID, slash, like, or Yeah, just like, and then it's gonna, of course, going to be a protected route, is gonna point to like, scream. And let's copy it, paste it again, this will be on like, and I've changed this to unlike as well. So let's bring these two functions that we haven't created them. So like screen. Unlike screen, one thing that I forgot to do last time. So here, where we post a screen, we need to actually get the image of the user as well, because we don't want to send another query to fetch it. So we can do user image here, we store the user image in the document of the screen. So user image equals request dot user. Remember in the last video, we actually did this image URL thing. So request dot user the image URL through the middleware, we're adding it. And we need to set like count initialism. So like count is zero, and comment count is zero as well, because this post has just been created. And when we create it, as well, as a response, we need to return it and not just return a message. So here when we get the document back what after adding, let's do const. rest on our response scream, I guess rest scream equals new screen. And here, let's do ress scream dot scream ID because we want to add the ID equals doctor ID. Now you might be thinking, whoa, this is a constant, how can you edit a key in it? But actually, you can add a key in the constant, you just can't change the data type or the complete value of the object. Alright, so here response to Jason, we just returned this rez scream. And let's quickly test that. So I already have Firebase running. Let's go to postman. We already have a token to hope isn't expired. So slash scream. Let's keep this open. Let's just copy this. Yeah, let's copy this here. Slash API slash scream to post the scream. So let's copy this token. Go to headers. Authority authour. Oh boy, authorization. bearer space that token I did it guys I spelled authorization properly. The body will be I don't know. Hello. Hello. Whatever. That's And, and cool we get Hello, hello the body will you use our images not image because this user does have an image yet, I get the scream Id like con created. Brilliant. Okay, so that's fixed. Alright, let's create the like function. So export, like a screen, split a comment here that says, like a scream, like a person could not understand from like scream that it's what it does, I don't know, request response. And here what we need to do? Actually, I want to explain something first. It's theory time. All right, what we're going to do here, because you might be thinking, Wait, why don't we store all the comments and the likes of each screen in the screen document itself. And you would be right in the sense that yeah, it makes more sense to store them in the same document. But the way databases work, you're supposed to keep each document actually really small in size, and try to spread all the properties. And the way Firebase in particular works is that it, it has a maximum of four megabytes per document that Allah allows you. And of course, if you would have a big social media website, let's say something like Twitter, one tweet could have 1000s of likes and 1000s of comments. So it would be extremely inefficient to store everything in one document, because it will be really slow to query that one document. And if you needed only a few properties, instead of everything, the way how query languages work, you need to fetch the whole document to get to get any properties. So it's more efficient to actually spread these properties, and have the likes and the comments in different collections and fetch them separately. I'm going to post in the description a video by the Firebase developers themselves explaining how you structure your database like this and why it's actually more efficient. And why it costs you less money on Firebase, remind me if I forget to pause the video. And by the way, I have one quick thing to say, Tell me, please let me know in the comment section if you prefer the, you know, the just code and let me write the code behind you. Because I just want to learn this framework approach. Or you prefer the approach where I actually explain the stuff that I'm writing, because I noticed I do spend quite a lot of time explaining some of the principles, but I personally think it's better for you to understand them. But okay, run over, let me know give me I'd like to get some feedback on that. All right, let's get to business. Let's create a collection called likes. And the way our likes are going to work simply each like will hold a user handle of who liked the screen. And another key scream ID of what scream they liked. Let's grab this ID because it's the only scream I have on my database. So let's put it here. And we could add a created art. But it's only useful for statistics and data analytics, because we just want to show the amount of likes, you can do it if you want, but I'm just gonna stick to scream ID and user handle for now. So yeah, we got likes now. And that means technically this. Actually, I have the other screen. So this screen now has one like by this user. Let's not worry about like count for now. Actually, let's worry about it. Let's just let's just Oh, it doesn't have it. It's okay, let's not worry about. Alright, so here, what we need to do is that we need to check whether a live document exists or not, we can't just add like we fetch, we query from our database. And if this like document already exists, we need to return a message to the user saying scream, scream already liked, you can't like it again. And as well, we need to check whether the screen itself exists. And if it doesn't, we'll be like, hey, the screen doesn't exist. You can't like a screen that doesn't exist. This function is going to have a lot of code. But it's it's good practice if you you need to take care of the edge cases. So we're going to get both documents right now and set them in variables because we're going to need to reference to them multiple times. And we don't want to like type a lot of this code again. So let's do const like document equals DB dot collection likes where the user handle of the like equals the user handle of the user that's trying to like again, or trying to like not potentially a lot again, so request dot user dot handle because this is protected again. That means we have access to that handle. And we chain another word here where scream ID equals request dot params because this is the idea of the screen will be in The URL itself, dot scream ID. All right, and let's do limit. One. Because this is a query, that means it's going to return a couple of documents. And even by the way, when we limit to one is still going to give us an array with one document, it's not going to give us one document. So let's do const. Scream document. Equals DB dot doc, slash, screens, slash, dollar sign curly braces, request dot params dot scream, ID. All right, let's do let's initialize that scream data equals an empty object. Do scream document. So first check is we'll check that document that this screen document exists dot get dot then doc. Here we do if if not doc dot exists. And return. Actually, let's start with doc exists, because it's more efficient to start with the case that what you think is more probable to happen. So if doc exists, then we need to actually give this scrim data this data, so scream, data equals, we don't have to actually ensure that as an object because it's going to become an object now, so scream data equals doc dot data, we need the scream ID as well. So we do scream data dot scream, ID equals doc.id. And here return like document dot get. And here we do else that means If the document does not exist to do return res dot status 404 JSON with an error scream not found. Alright, so after the then No, not catch, we have another one. Because we did return like document. So this will give us a query snapshot. So data, if so data has an empty property if if the array is empty, so if data are empty, that means we don't have the life so we can't actually create it. So let's do return DB dot collection. Likes, likes like this dot add. And here we pass an object. And this object will have a scream ID of request dot params dot scream ID and the user handle quest dot user dot handle. And the thing is, we can't do return here and and then handle the promise in the next two then. Because this, the problem is that even if it's not empty, it might, it might actually go through so we're actually gonna put we're gonna nest the than inside of this if block to avoid that problem. So we're gonna do them scream, data, dot, like count. So we're going to increment the light count, because we liked so we're going to increment the life count of the screen by one so we do scream data that light count plus plus. So let's do now. So now we've already added a like to our likes collection, what we need to do is we need to actually persist not persist, add increment the like document, sorry, the like count in the property in the light in the document of the scream in the database, oh boy, or ice cream, God document dot update. And we need to update one property, which is the like count. And we set it to scream data like count, because remember the screen data equals the data that we got from the screen from the database. And we've already incremented the light count here. So we just passed this here. And and here we chain another one. And this returns a right result we don't need. So we're here we just say return res dot Jason. So here Everything was successfully so we return the screen data to hold the screen and Yeah, without any likes just the screen with the new like count. So here, this f block, let's do ELS, that means we have no likes. Rather, we have a like in this data array. That means we can't like this because it's already liked by this user. So return res dot status 400 and dot Jason. And the URL will say, scream, already liked. All right, so after this, then we do catch error, res dot status 500 error code. That's console error as well, I don't know why I'm formatting because prettier is gonna format it anyway. Alright, let's save all of this. And let's save this. Let's comment this because this unlike doesn't exist yet. Or let's actually create it and just return nothing. Or do we write the whole thing? Screw it, let's write the whole thing. So exports dot unlike, and I did say Screw it, I'm keeping it PG. Alright, request response. const is very similar to, to like, so we can actually copy everything. Now I know, I could do everything in one function the like that. But unlike but the code will get too massive. And we could just add another route doesn't harm anyone. So here we are the like document, same thing, scream document, same thing, let's cream data. But here instead, it's the opposite down here. So if the if the data is empty, this is where we return the error. So let's copy this return. Let's go here and say, error, scream, scream not liked. Because we can't unlike a scream that we haven't liked yet. Otherwise, if we do have something in that array data array, what we need to do is we need to delete the entry. So let's remove all of this. Let's do DB dot collection. I do we do that? Oh, we have the path for it. So we need to do is that DB dot collection likes dot actually dot doc. We haven't done this yet. dB dot collection dot doc. So this already adds the slash thing. Or maybe we can do this. Let me try something to make it more simple. So DB dot doc, this backticks slash likes. Slash and remove this bit of code, then we add data, the array of data zero the first member of data that actually know what am I doing data dot Doc's zero, because this is the the array dot data, the function.id should give us the ID. So this is the actual path for that document. And we chain delete, which will delete the function, the document rather. And then here, we chain them inside of this block. And then this we don't need the right result to a scream data dot like count minus minus two decremented by one and we return scream document dot update. Like count is scream data dot like count. But the column here screen data dot like count. And then as well here. And we'll say we just return a response res dot JSON. We return actually the screen data. And here after this, then we have the catch. It's gonna have the same error. Cool. All right, so unlike, unlike scream is done as well. So let's save everything. Make sure you're running. Let's go to postman. So here we already have an author. And token, because we were trying to comment now we will try to actually like slash like, and let's not send any body and it's a get request. So let's send this Okay, it says scream already liked, because we added to that document. So let's actually put them side by side. So you can see updates in real time. Let's do unlike, let's try to unlike this comment, the screen. Okay, there's an internal server error. dB doctor delete is not function. Oh, did to Wow. All right. Save. You probably didn't make this make this mistake. All right. Oh, that's weird. It didn't delete the actual like, and the light count is No. Oh, it's because the screen itself it didn't have a light count in the first place. Let's give this a value of zero as decrementing the light count, but it's not deleting the light itself. Okay, let me have a look at this and come back. Okay, it's actually this dB, data dot Doc's not the data, the ID is actually stored in the document reference and not in the data itself. My bad. Okay, let's, what we're gonna do is we're going to go to the screams. So this what scream was it was the scream, or was the scream. So let's put the like count to one because that's what it was because there's only one like, and it's on that screen. And let's send the like, again, it should say scream already liked. Cool. Let's do unlike cool, it deletes the document. And if we go to screams, it decrements on Oh, it's this one decrements the light count to zero. And if we send like, it increments the light count to one. And if we go to likes, he created the like document a different like document but with the same credentials, which is we're already here. And this video is not that long yet, we could keep going and created the Delete screen route. But before we do that I want to fix something on functionality that's missing is that here when we comment on the screen, we actually have access to the screen documents. So we could actually just increment the comment count right here. So here instead of this return collection, thing, let's cut this. And let's do return document, which is the scream document. And here to use the update function, we have to add the prefix reference and use update. And here we need to update the comment count. So let's do an object and comment count. Who should be equal to doc dot data? dot comment count, which is the current comment count plus one. All right, so here, let's change a dot then to have the right result which we don't need. And then here we paste back the adding the comment. So DB dot collection comments, add new comment. Alright, so this should do the trick. And if we go to our database, we see we have three comments all on this screen. So if we go to that screen, actually, this screen doesn't even have a field comment count, because it was created too early. So as to comment count, and it's a number and it has three comments. So now if we submit a comment to this, we should see this comment count increase increment by one. And of course the comment would be created. So we have the idea right here. Let's write comment here. Let's get a token. Well, we already had to talk about what it was take that new token. Let's go here and how does come all the way here paste the new token. And we're here it's comment and comment is a post route. So post In the body, a say comment number four, that sand. And this look here. I mean, here a core common count has incremented by one. So we have four comments now. And in our comments, we have a new one comment yet. There we go. Comment number four. Great. Alright, so let's write the route for deleting a scream. So in the index, let's instead of this comment, let's do app dot delete, because it's a delete request. And it's going to point to slash scream, slash scream, colon, scream, ID, of course, gonna be a protected route. And the function will be delete, scream. Let's import that. Delete screen. Save go to screams here at the bottom. Let's do a comment, delete. I always misspell the word ScreenFlow delete for some reason. Alright, so exports dot delete script, delete. I hate the word delete. request response. And we need a reference to it. So const document equals dB. Doc backticks slash screams slash dollar sign curly braces request dot params dot scream ID. Now here we do document. dot get the band get document. And here we do if not, Doc dot exists. Well, if it doesn't exist, we say make it doesn't exist. You're trying to delete something that's already been deleted or potentially never existed in the first place. So restart status 404. Jason error, the good old not found. Oh else if it's found. What do we do here? Actually, here, we need to check. Because we need to check that the ID, the user ID of this screen is the same as the user ID of the user decoded from the token, because we need to make sure that this user is the actual owner of this screen, because you can't delete someone else's screen. So we need to check doc dot data dot user handle has to be. So if it's not equal to request the user dot handle, because we already have that through the middleware, we need to return rest dot status 403 unauthorized with a Jason with an error of an authorized else we're return document. This is why we actually put it in a variable because we needed to. To use it again. Delete oh boy misspelled delete What's happening? Then I need a button on my mouse that whenever I click right to delete, because I don't like that word. Okay, so a message would say scream deleted. Yes, I did it success fully. Alright, let's catch just in case console. dot log, log or error. Response dot status 500. json error, error code. Alright, let's test all of this. And we're already running. So let's go to postman. And so I'm user. And this Alright, let me make sure. So let's get the screams. So this screen is by user and I'm logged in as user. So if I send a delete request to this scream slash, the scream ID slash delete. We should Actually successfully deleted? Wait, do I actually we don't need this delete? Because this can be the same. This can be like this without the extra path here or not here, here. Where are we? Okay. Oh, we don't have to delete. Okay, my bad. I confused myself there. So if I send this it should successfully deleted. Cool. And it does if we go to our database that scrim is gone. Yeah, the screen is gone. If we tried to do it again, it should say scream not found. Brilliant. I have a question for you. How can we have a social media platform without bombarding our users with notifications? Answer, we can't. So let's implement notifications, I want to start by explaining something. So if we go to screens right here, you see when we like a scream, or unlike, it's already like a bunch of requests to the database. Now, notifications don't have to arrive instantly. So we can handle them separately. And we can do so by taking advantage of something called database triggers. So if you go to File firestore documentation, and you scroll down to triggers, there's a bunch of different triggers on authentication, or real time database on an on firestore. We're interested in the firestore one. So basically, these are kind of like events that watch changes in certain document a document. And then on those changes, it triggers an event and it does something. So you have onCreate on update on delete, and on right. Alright, you can read the documentation page, I'm not gonna talk too much about the theory, let's actually implement this. First thing is we need to have, we need to create a notification whenever someone likes a post. Okay, a scream is not a post, what is a post? That's not a thing. All right. So export dot create, I'm really trying to push the idea of like a scream is like kind of an ape screams and a bird tweets like Twitter, and this would be different. But yeah, anyway, so create notification on like, and this would be equal to functions dot, and I'm going to change this region function, maybe you don't have to, maybe you do. So check with your depending on your case. So I'm going to add the region, Europe or west to, and I'm going to chain here the namespace, firestore dot document. And the document we're interested in is in slash likes, slash or slash, could just do likes slash, like this ID in curly braces. And here our event is the onCreate. So whenever a document is created, and this will have a handler that will take a snapshot and a context, for us, we don't need the context, we just need the snapshot, which is basically a snapshot of this like document that has just been created. So here inside of here, let's do dB. We can't do dB, because we haven't imported it yet. That's important. So const dB, equals require. And if you remember, this is in the util. So dot slash on the same level, flush utils slash admin. Okay, like this. And here, we do DB dot document. backticks slash screams, slash, we want to get the scream. Because we need some data from the source slash scream slash snapshot, dot data. dot scream ID remember that this is the like document, so we have access to the scream ID. So don't get returns a promise, then this will hold a document. So here we need to, we need to add this check if doctor exists. Now of course, it's always going to exist in this case, but it's just good practice to add, still return. Now inside of here, we're going to create a notification the reason why we fetch this screen, because we need some data from it. So because we need the the owner of the screen the handle of the owner of the screen, so let's do return DB dot collection, or actually, db dot doc, because we know that it's going to be in the notification. So notifications, make sure you don't misspell anything. Because they sometimes do that you'll t snapshot.id now we're gonna give the IDE, the notification the same idea as the like or the comment later on. And I'll show you later why this is useful. So we do not set And inside of here, we're going to have a created art, which is going to be new date, dot two, ISO string. And we're going to have actually let me copy and paste this for you to use as a reference. So let's go to dB schema. And under comments here, I'm going to paste this. So this is what our notification is going to be like, it's going to have a recipient, which is who's getting the notification, a sender who's sending it a read of true or false by default, it's false, because it hasn't been read when it's created a scream ID of which scream does pertains to a type. In our case, we only have likes and comments. So two types, and I created that. Alright, let's go back to our index. So we have a recipient. And it's going to be the doc dot data of this, because doc refers to the screen remember, dot user handle. And we have a sender. And it's gonna be the snapshot dot data, which is the like document, the user handle. We're going to have a type. In this case, it's a like, So type is like a read of false. Okay, this is five things, let's check if we have covered everything 1235 we're missing? The Scream ID, curse, go back. Scream ID is the snapshot. Or let's just do use the document can use both. So let's do doctor ID, which is the screen call. So this returns a promise that holds a What does it hold? Right result, I think, but it doesn't matter, we're gonna we're not gonna need it. So I can just leave that empty. And we could just say return. And here to do catch error. case an error happens, we just, we don't need a block which needs to console error. Actually, we do because we need to return. Alright, console dot error, the error and return, we don't need to send back any response because this is a database trigger. And it's not a an API endpoint. Let's create the next one. So here we need to do create notification, do the same name, but we change on like to uncomment. This will be functions dot region. Again, I may copy this, but here functions dot region. And the document will be in comments slash ID. And we're going to listen to on create as well. And here we're going to have a snap shot. And inside of here, we're gonna get the scream again. So it's kind of the same. So I'll just copy all of this. And here we get the document, we'll check if it exists. And we create a notification with the snapshot ID, which is the comment document ID and created the same recipient is the same, sender's the same that type is comment. First change this to comment. The doc ID is the same, everything is the same. Cool. So I'm going to keep going, I'm going to create all of them, and then we're going to test them. So let's save and then underneath here, we don't have the ability to delete comments. So we don't have to worry about that. But we have the ability to unlike post, actually, I'm going to put it here. So we need to because the thing is we're going to create notifications. But if someone unlikes the post, we want to delete that notification. I don't want to use it to have a notification for some that someone liked their post. And then after they unlike it, they still get the notification and then they go there and they're like what no one like that. Alright, so this is going to be called delete notification. On on like, like this. So it's going to be a functions. Guy. Let me copy this bit. So functions that region a document and the event is going to be on delete a snapshot. And what we need to do here is we just need to do DB dot doc and backticks slash What is that? Okay slash notifications slash snapshot to idea remember because the it has the same ID the ID of the Like is the same as the ID of the notification that pertains to that, like slabs slash snapshots slash ID dot delete. This returns oops, this returns a promise that holds a right result that we're not going to use. So we just leave the thing empty. And we do return inside of her. And I do catch error, console dot error, the error, and then return. All right, let's save. And these are DB triggers that we need to deploy for them to work, save this, make sure you in the functions folder and let's do Firebase. Actually, I think the command even works from the root folder. So I don't know why I always have to go into functions. Okay, now that it's deployed, let's go to our functions in on Firebase. As you see, we have our DB triggers. Let's go Let's copy the endpoint and let's go here. Let's login or let's actually create a new account. Because why not? So sign up? Just test out just in case the functionality for adding the default no image picture. and stuff like that Confirm Password. Same. And the handle will be Jane. All right, we sent the post request to slash sign up. Oh, email is already in use. Let's just use like new to. And the handle is new to send. Excuse me. All right, let's take this token. And let me make sure that the ID is still correct. I didn't delete that screen. Okay, so we have one screen that starts with q Ed. Yeah, the ID is correct. Because this is a new account. That means we have like that yet. So we'll change the endpoint to slash like, oops, not here. And in the authentication, we do bearer, and we paste the token, and we send a request. All right, so like count incremented to two, we should see a notification collected, collection created and a notification created in a second. Alright, so the notification has been created. Let's actually unlike that post, or that screen, and see if the notification is removed. And it is removed. Alright, so let's post a comment. And see if we get a notification when we post a comment. Let's change this to a post. And we have a raw body of type application Jason, and we're gonna have a body of the comment will say, nice scream again, as opposed to comment. Alright, we get nice screamer, get our comment back to us. And we should get a notification created here. We do our get our notification and click on assess type comment, and it has the correct recipient and sender. The sender was new to the account we just created and the recipient was user which is the owner or like the person that posted the screen. Cool. So everything works. One other thing that I wanted to edit is in the users handlers file. When we get authenticated user here, we return the user and the likes, we need to return that their notifications as well because we need to access them and show them on the front end. So let's add that. So here instead of returning user data, we need to do return DB dot collection. Notifications. Where recipient is request, use the handle and we order by the created art date in a descending order and we limit by 10. I want to limit to just 10 you can Not limit if you want, and then we get them. So let me make sure I didn't misspell anything. All right, so here we chain another gun. And this will have a data. So we'll do data dot, let's actually initialize user data, dot notifications equals an empty array. And here we do data dot for each document. User Data dot notifications dot push. And we actually need the notification ID as well. So what we're gonna do is, we're going to push all the fields one by one. So let's do, what do we have? I put this on the side, just remember what we have. So we have recipient is doc dot data, dot recipient. And let's copy this and paste it like 123. Okay, five more times. So we have sender, we have created art. We have the scream ID, that type and the red. And we also need the ID. So let's say notification. Id is doc.id. And so after this after the for each loop, we just do rest, or return res dot Jason, use data. Let's test this out. Let's Login as user because user right now is the only user that's got any notifications. So let's change that to login. And let's delete these two keys and change this to user at email calm. So we get our token, let's send a get request at slash API slash user. Actually, we need to either deploy or, or serve I'm going to serve right now. Alright, if you said make sure you're on localhost and not the deployed one, let's send the request. And error nine oh, it's because we need to create an index. So let's copy this URL. Because it's like a complex query, and we need to create an index for it. Create index, this will take a couple of minutes, so I'll be back once it's done. Alright, so our, our indexes not created. So if we send this request again. And there we go, we get our credentials, and we get our notifications as well. And if we had any likes, we would get them here, but we don't. Cool. So this is working. Alright, there is two more routes that I want to create for users. Before we finish off this video. Let me close this. Let's go to index dot j s and create two routes here for users. One would be the route where we use to get a user's details like another user's details or even our user. So this is, say, app dot get. And it's at slash user. Or let's say yeah, slash user slash colon handle. So this is we pass the handle and the application gives us back the details of this user. And this is a public route. So and we're going to call this function get user details. And one other one is app dot post, slash notifications. And these names don't matter. By the way, these are not front end routes. These are not what the user sees. These are just what we send as requests for our back end. So slash notifications, and we'll call this mark notifications. Red. Let me make sure that I spelled that correctly. Yes. Okay. And this is of course protected. Let's add these two and we will create them in a second. So here and users, we have get user details, and Mark ratifications read. Alright, let's save and let's go to users and create them. I'm going to put the get user one here. So let's call this get another or any user There, any user users details will be exports dot get user details. It's gonna take a request and a response. And let's initialize a C user data cause an empty object. And here we do DB dot doc backticks slash users slash, dollar sign curly braces to put a variable request, dot params. dot got. Handle? Yeah, we call that handle. And here we do not get so we get this user, though, then we get a document. And here we are the credentials. But of course, let's first check if the user exists. So doc doc exists. And here we do user data dot user. equals, do we need to initialize this? No, I don't think so. So do user that doctor data. So this is our user data. And here we do return. Now we want to get their screams. So return. Remember, this is the Users page, we need to see that screams. So return DB dot collection, screams and where user, as a user, user handle the ID is a handle equals. So we have this in our request, params request dot params dot handle. And we need to sort these as well. So order Order, order by created at descending, we might have to create an index for this. So get, so we're going to return it. So in the next 10 block, we're going to have data. And here we initialize user data dot screams as an empty array. And here we do data dot for each. And we get a document here for each document, we need to do user data screens. Now here, we could just push the data, but we need the ideas. Also, we need to do the screens that push and we create a new object. So we need the body of the screen. Doctor data dot body, and let's copy this. And so we have a created user handle a user image, like account and comment count. And here we have scream, ID equals dog.id. So what did we say created art? Don't forget to click Control the user handle user image? Like count, and comment count. Alright, so I think this is Yeah, this is it, we just need their screams. Alright, so after the four H, we need to do return risk response dot JSON user data. And here after the done we do dot catch error. Console dot error, the error and return res dot status 500 500 dot Jason Error Error code. Alright, so this this is sorted. And I'm gonna serve just to start creating the I was already serving, what am I doing? I'm going to serve and test this just for it to prompt me to create the index and then let it index. Let it let's create and then we're going to create the mock notifications read route what's happening. Right post requires a callback function but got an object undefined. Oh, because we're not we haven't created this function yet. Let's just comment this out and try again. Of course, let me remove it as well from here because there is no export for that. Actually When not handling if the user if the document doesn't exist, so let's do an ls here. So if the document actually doesn't exist, we need to return a response return response that Jason, or that status first of 404. But Jason error, user, not found less safe, and it's gonna serve a gun. And here, let's do a get request without any authorization header, slash API slash user. And we get let's see, Jane, do we have Jane is found Actually, I didn't delete the account itself. I just deleted the entry in user stable. We have Johnny I'm pretty sure. Oh, it's gonna give us the error for the index, I think. Can I misspelled something? status. But why would it get here? Oh, yeah. Okay, there we go. So let's copy this and create the index. Okay, while this index is being created, let's create the other Mark notifications read function. So exports dot Mark notifications read. Now the way this is going to work is that when you open a sec, when you open a drop down, that has a couple of notifications that are not red, we were going to send to our server a an array of IDs of those notifications that the user has just seen. So we can mark them red, so they're not marked as unread on the client side anymore. So we're here, we're going to need to need to do something new called a batch, right, which is in Firebase when you need to write or update multiple documents. So let's do let's let batch equals DB dot batch, like this as a function. And let's do request dot body. And here we're going to have a property called. But actually, we're going to have an array as the body. So let's do for each. So our body is an array. And for each notification, and here, it doesn't matter. We can call it anything but let's call it notification const. Notification equals DB dot doc. And where slash notifications. Remember, this is backticks. So I can use this variable notification. Yeah, notification, this one. But this is an array of ideas. But let's so let's change this name to notification ID, here, notification ID, so it makes more sense. So now we have this document, we need to do batch dot update. And this, I misspelled that update. And this is gonna take a document reference, which is the notification that we just created there. And what we wanted to update. So the key is read. And we want to make it true because the US has just read this. So once the four H is done, we can do batch dot commit, oops, commit, which returns a promise, and we do then doesn't hold anything, I think and we just return response that Jason, Jason and it's going to have a message. Also notifications marked. For read. Write and catch. Doing it. Return response. Yes. So let's say console. dot error, the error. Okay, so this is done, Mark notifications red, and let's bring it back here. So Mark notifications red Let's uncomment this route. And what we need to do now let's, okay, so the index has been created. So we can send this request to get the data of Johnny. And we should be able to see the data of Johnny here. And we do cool. So we get users and we get the screams, he doesn't have any screams, user has the screen we should see here. Cool user has a screen. Alright. So let's try to get so user has some notifications, right? If we go to our database, no authentication database. So notifications, user has one notification, let's actually add another notification for user somehow. How do we do that? Let's log in as john, or Johnny. Let's get Johnny's handle or but or let's comment, actually, so we can comment on john. As Johnny, we can comment on users scream. So here, we'll say nice scream from Shawnee, and we send this post request. Yeah, nice screen from Johnny. And we go here, find that there is a comment. Actually, there's multiple comments on the same post on the same screen. But we don't have Okay, now we have two notifications. So let's take these IDs. This is why we needed to send back the ID of the notification, because we need to use it when we want to mark it as red. So our body is going to be of type Jason is going to have an array of strings. So the first string is going to be this ID. And second string is going to be this ID and remember that they are false. They have false for read. They're not read yet. So this is the second ID. And we need to send this request at slash API slash notifications is a POST request. And we need actually john is token. Actually, we need to use this token. All right, we send this actually slash API slash notifications that I make a mistake. Okay, I misspelled notifications. Let's send this request. We get notifications marked red. And if we look at our database, they have true for red. Cool. So this is going to be the last video in right in the backend of our application, we're going to add two more DB triggers to finish up the functionality of our server logic, or our server less logic, I guess. But before we do that, I want to fix a couple of things. So let's start with users. Let's go to users dot j, s and in the signup, so here, here in the sign up, we here at the bottom, when we return errors, here, if an a server error happens, I want to actually return something to the client. So let's say General, not error like general and I want to say something went wrong. Please try again, just in case this happens, we will show it in the front end. And one of the another thing here when we handle our E authentication error in login, we want to we don't want to check for this password thing. We just want to return in general wrong credentials. And by the way, if you want, there is two status codes to error status codes, two main ones related to login in the whoops, the auth wrong password, and the auth user not found. It's not recommended, but you can actually use them to show on your front end that either this user doesn't exist or it's the wrong password. But I'll stick to the safe just return like this just return. General wrong credentials. Please try again. But you It's up to you. What do you want to do? Alright, so two more things in Scream dot j s, all the way up here in get all screams, we want to get the user image of the of the post so that we can show it in the postcard. So Doc, user image equals doc dot data dot user image. And down here in comment on screen, when we validate the body, we want to return the error, comment must not be empty. All right, cool. So these are the fixes. Now, let's add our DB triggers. But actually wanted to fix more stuff here. If you have been wondering why you've been getting these weird errors from our DB triggers saying function returned, undefined expected promise or value. I tried before returning zero and it doesn't work. You either return a boolean value like true or false, or you just return a promise. So what we're going to do on our triggers is here, for example, in Well, we're going to change all of them. So here, when we do our promise, here we are the return in front of it. So we return this promise. And don't worry, just because we wrote return here doesn't mean the execution stops here, we actually get through here. And then here, when we return this promise, we don't do another dot then and return nothing, we just do like this. And we don't return anything when console and or we just do that. And in delete notification, we actually do return DB dot doc, dot whatever dot delete, and then we remove this then block. And here as well on create notification on comment, we return DB dot doc, and we remove this block. And one thing that I wanted to fix, I noticed that we are creating a notification on like an uncomment, even when we like our own posts, which is obviously not a good thing. So what we need to do here, when we check if document dot exist, we also need to check that the ID. So not the ID the handle of this, for example of this, like is not the same with the handle of the post. Because what this would mean it would mean the person that liked to dispose, this is the same person that posted this scream. So we don't want to notify them if that's the case. So what we want to do here is, and no, not here. So if doc exists, and doc dot data, dot user handle, so this refers to the screen does not equal snap, not spawn, snap shot, dot data dot user handle. So this would be the like, actually, that make make sure it's user handle. So likes, yeah, they have a user handle. So if we do this, and we would copy this, and we would go to create notification on comment, and we do the same right here. Now we no longer get notifications if we like our own post or our own scream or comment or our own scream. Alright, so now I want to add two more triggers. The first one is that, what I want to do is that if a user so for example, right now we have screams and each scream has an image URL, user image of the user image at the time they created this screen. While I want to do now if the user changes their profile picture, I want to add a DB trigger that actually changes the user image of all the screens submitted by this user to show them as well on the card. So let's add a new new trigger here called Expo called while exports dot and we're going to call it on user image change. And this will be a functions. For me, I'm going to region, Europe, West one and firestore dot. What is this going to be? I think it's Your Honor, not on update on update. And we will the doc we're on update. We actually I forgot to change document. So document. So we need to say first what document we want to listen to. So slash users slash curly braces, user ID. And then we want to say on update, so on update, and this will take a change and context. We don't need context. So we just take change. And what's cool about this change object is that it has two properties. So let's actually console log them. So you see how This works. So to console log change dot before dot data. And if we were to just copy this, and then type after here, it's exactly that this snapshot has two values, the before it was edited, and then the after. So we can compare these and we can see what actually changed. So what we want to do here is we want to change the image of the the posts that this user has created. Actually, this is we're going to change multiple documents potentially. So we need to do a batch, not read write a batch, right? So let's do lead batch equals DB dot batch. As a function like this, and then here, we do return DB dot collection. Screams what whoops, what is this? What am I doing? Okay, so where? What does it use a handle? Equal equals? What is equal actually? Yeah, change, we have the data and change change dot doesn't matter which one we use, because we can't use we can't change the user ID or use the handle anyway. So change dot before dot data, dot E, it's just handle in the document of the user. And we do get and then here we get data. So data dot for each. So for each document that this user has created. To do const, scream equals DB dot doc backticks slash screams, slash, dollar sign curly braces doc.id. So this is the document. And here we do batch dot update. And we passed the document, which is scream. And our change would be user image will now be change dot after. So this snapshot of after the change of this user document dot data dot image, URL. Alright, so here after the forage, yeah, we're after the forage here. So we do return batch dot commit. Yeah, that's it. So Oh, actually, oh, we need let's, we need to only do this if the user image or the image URL has changed, because the user can also change the, what we call them the details like the buyer, the website and the location. And we don't want to run this batch, right? If they didn't actually change the image. So we'll want to do here if want to do it, want to check if change before data, dot image. URL does not equal change dot after dot data dot image URL. So we'll execute this only if the image URL of this user document has changed. Let's do a console here just to make sure that it's only executing on the image changes. And merge has changed. And yeah, I believe this is zero, we can actually test this. Yeah, but actually, that's right, the other trigger and unless this both of them to save time, I don't want to make this video long, because the last one was quite long. So export that. So for this one, what I want to do is a problem is that if we have screens, and each screen could have likes and comments and notifications, and if a user deletes their screen, what I want to do is that I want the trigger to delete all the notifications, the likes and the comments that are related to that one screen that was deleted. Alright, so we'll call this expose.on scream, scream, scream deleted. On scream delete, two functions. Let's copy this. I don't like writing this. I still functions, functions dot region, the same document screams scream id.com On delete, and here we gonna have a snapshot and the context. I have an arrow function here, we're not going to need the snapshot, we're just gonna need the context because the context is, has the parameters that we have in the URL. So let's do const. Scream, ID equals context, dot parents, dot, scream, your scream, Id choosing the URL. And let's do our batch here. So const batch equals actually here, we could have made it into a const as well, because logicals that, so batch equals DB dot batch. So function like this, and now we do return DB dot collection. Let's start with comments. comments. Were the scream ID equals scream ID dot get. What is it? Yeah. Okay, so get that then. And then we have data. Now data for each. Doc. Let's do Can we do it in one line? Yeah, batch dot delete. And we can say DB dot doc. backticks slash comments. Slash dollar sign. doc.id. Like this? Yeah, this is I think this is such comments slash doc.id. Yep. Now we need to also after the forage, we need to delete as well, the likes, let's do return DB dot collection. likes my God, where scream, ID equals scream, ID. I think we can copy this block. And then we just paste it and what we do here, delete, slash, like slash doc.id, like this. And then so we've looked for comments, and then deleted them. And then we looked for likes and then deleted them. Now we look for notifications. And then paste this oops, not this. Let's paste this block. Yeah, so we paste this block. And so data and delete slash notification slash this ID. And then here we just return batch dot commit, like this. And we do a catch block, batch error. Console dot error, the error. All right, so we have to deploy because these are DB triggers. So fire base deploy. Okay, let's test out our so what's cool about dB triggers is that we don't have to actually just send a request, we can change stuff in the database here on the interface, and it will trigger the DB triggers. So if we were to go to this, okay, so this screen was submitted by user, let's change the user, the user dot image URL right here. Alright, so let's change this from oops, no image to no image is like with an S, even though that this image doesn't exist, but the database knows nothing about actual images. So let's look for change here, this should change to no images, and it does cool. So the DB trigger is working. And if we go to functions, and to logs, we scroll down you see this is the before, and this is the after. So this is the before and you see here the before had no image and then after had no images. So these are the before and after. And here the image has changed was triggered. This, this conditional, actually here in the F we need to do as well and else is to else return true and K Actually it goes through this because it can go if the user just changes their details. Or if I were to go here and change something that's not the image URL. Clear, let me open this on a different window. So I don't keep waiting for it. So here for it to go to user and change something else. Like, I don't know, location would be London again. And I'll do update. And if I were to go to screens, of course, nothing changes. And I forget to go to the logs. Because that trigger will still happen. Yeah, the trick? Oh, but I think it's because it hasn't been deployed properly. So. Okay, let's just change something one more time. So let's change for example, now the email the website from google.com, to Twitter. And then if we look here, we're still Oh, we're still getting function returned undefined because it went through here. And this, this was not satisfied this condition. So we didn't return anything. But with our newly deployed code, this, this problem should go away. It doesn't, or does it? Oh, it does. Okay, so we get before we get after. So here, we changed Google to Twitter. But image hasn't changed. So that block of code, of course, didn't get executed. Cool. So let's test out as well as deleting our own post. So we will log in as user because user has this scream. And then there are these notifications that are related to this screen. So you see the ID is starting with 14. And it's this post. And here the likes are these two likes are related to the screen, and then this comment as well as related to the screen. So if you were to delete the screen, all these comments and likes and notifications should be deleted. So let's make sure that that's the case. So we log in as user. We take the toll token. And let's do slash API slash scream, scream, slash and then we change this to a delete request, we remove the body and let's get the ID of the screen. And we do this and this should delete the screen it says unauthorized or because we didn't add our snap, I have to log in again. We didn't add that token and now I don't have it in the clipboard anymore. Sorry, guys. I changed this to a post let's get token may put the token in the authorization spell this correctly. Or like this authorization cool bearer token and then change this to a delete take the ID from here to slash scream slash that ID and that's a delete with sundered scream deleted successfully and then we go here. So everything should be deleted from these three collections. Okay, I must have made a mistake in the code. Okay, it says in the log it says data dot four H is not a function. Oh, what am I doing Of course, here when we return these DB dot collection dot whatever. Here of course we do get can't get anything without chaining get after it just like here. Okay, it should work now. Let's save and let's deploy my bad and we need to create that that screen again manually because it's deleted now. So let's get the ID of that screen from here. Screams are the collection is gone because it was the only scream that screams and the ID is this Sir. And what's gonna have a user handle? user and a body? How this is the screen? What else we need the created art. It doesn't matter. It could just be anything. Let's give it actually a string. I don't know just this. Give it a like count of three or two, number. These dogmatic guys we're gonna delete anyways. Why did that one go away? So on those one, okay, I think this is it? Yeah. Alright, we'll create it. Let's try to delete it again, this code has been deployed. And this time when we delete it, it should actually, the our code should delete the notifications, the likes and the comments. So let's send this request. Scream deleted successfully. All right, dedications, deleted, comments deleted, and likes deleted. Sorry about that mistake, guys. One more thing, though, if we would go to the Google firestore REST API documentation page, you could find that this is basically a REST API that any firestore or Firebase application can use to access their database. So it would actually copy this endpoint right here, up to slash documents. And we're to go to postman and paste this here. And then get our project ID can get our project ID from our config file. So this is our project ID. Let's copy that. So if we paste it here, and we do, let's say documents, slash screams, and send a get request, it will actually, oh, we have no screens. Try users. Yeah, I'll actually get our users formatted in a different way by we'll still actually get our users which is, of course, a big No, no, it's a big security hole. So let's patch that hole. So if we were to go to Firebase on go to database, and then go to rules. Here, because what we're doing is we're using only the Admin SDK to access our database. Here, instead of allow read and write we can say allowed read and write colon, if false, which means don't allow, read and write basically, so we're locking down a database. So now if we were to go back to postman, and we send this request, it will say unauthorized. But if we were to send a request at our endpoint out our API endpoint at slash screams, we will still get our screams. Now we get an empty array, because we have no screens right now. But it's a 200, we did get the data from the server. So yeah, this is the last thing that I wanted to add to actually finish off the backend. So yeah, guys, we're done with the back end. And now we will start working with the React applications. So look forward to that. In this video, we're going to start to create our react app. And we're going to get create react app to scaffold all the boilerplate needed to run our application. But before we do anything, I want to show you something. So I didn't emphasize enough the point of why we had to write all the backend in Cloud Functions instead of using the Firebase client library. So this is basically our event of eventual bundle our complete project bundle. And this is, by the way, a tool called source map explorer that you can use to see which packages are have which size in your bundle. And I'm using it to look at the final bundle of our application, which will be 457 kilobytes in size. And as you see here, material material UI has 171 kilobytes from that. And the rest are all necessary stuff that we need. So this is the bare minimum that you we can use to actually have the full functionality of our application work properly. And or should we compare this to something like this, which is a project I've worked on before that has very minimal functionality, actually, but uses the Firebase library Implementation Firebase client library to actually access the Firebase database and perform operations on there. If you notice, this package is 907. This bundle is 907 kilobytes, which is double the first one. And Firebase alone is almost 500 kilobytes of that. And stuff like react, Redux Firebase is 60 kilobytes. So you see how using Firebase on the client can inflate the size of the bundle by a lot. And this is important for many, many reasons of which you can use services that charge you with by bandwidth, like a most notably AWS s3. So you will get charged more because your users will request bigger chunks of data. Second is if you're shipping your single page application to slower mobile devices, they will have to unpack this massive JavaScript bundle. And, and by the way, this project doesn't even have material UI and and the other stuff that we're using in our project, so this will be more than one megabyte, which is, which is kind of a lot for a react app that of this scale. So yeah, I just wanted to show you this quickly. Alright, so let's actually start to create our application and the desktop here, I'm gonna open up Git Bash. And if you don't have create react app installed, you can just Of course, you have NPM installed, I'm assuming you can just run npm install dash g create react app, I already have it, so I can just run create react app, and then the name of the directory will be social, a dash client. Now, this is gonna take some time, so I'll be back once it's done. Alright, now that it's done installing, we can see the interior. So CD, social, a dash, would we call it? client? Yeah. Okay, let me open it in VS code by running code dot. Alright, so create react app comes ships, a, a web pack development server that's already configured for us. So we can just run NPM start, and it will start our app. Let me open up here. Alright, so this is our app right now. Nothing fancy. Let's clean up the stuff, we don't need this logo, so we can just delete the logo. So let's delete this. Surely I need this font family thing from here. I'm just going to delete this file, go to the app CSS, just delete everything. But here, I'm gonna keep that font family thing just in case, the user doesn't have the Roboto font, which is the main font that materially we will use. So let's go to index CSS, js and remove index CSS from it. Go to App j s, remove that logo because we deleted it. And here, I'm just gonna say I'm just gonna have a header one that says up. Alright, let's save all files. All right, cool, are up. Let's, I want to change the icon here and change the name of the app. I already have the icon downloaded, but I'll post a link to this in the description. So if you go to our app, public, we paste it down, we delete this favorite icon thing. And let's go to public index HTML and change fav Ico to icon dot png, or whatever you named it, I named it that and change the title here to social ape, save, go back and everything's changed. Cool. Alright, so here in the sole source folder, there are a couple of conventions on how to group your components, I'm going to have two folders, one that's called pages. For the actual pages, we're not going to have a lot of pages, it's going to be like five of them. And here we're gonna have components. So I'm gonna put I'm gonna create three pages for now. So home the J s and the pages I'm going to have with lowercase with camel case, I'm going to they're going to start with a lowercase letter basically. So I'm going to have home j s login j s, and sign up dot j s. Alright, so here, because remember guys I'm using es seven react Redux graph. qL React Native snippets extension. I'm just gonna sorry for reading the whole name. I don't know why I did that. Just gonna Do RC E. So this is a class based component and it's already exported for us. And here I'm gonna have a header one that says homepage. Let's copy the whole thing, go to login and change this to Ctrl, D Ctrl. D and do login. And then paste here and then do Ctrl, D Ctrl. D, login, or lowercase login. Oops, no, this is sign up. What am I doing? Sign up? Cool, save everything. Let's go to App j, s. And here, I already want to install react router Dom so that we can have our different pages in different routes. So I'm going to open up a new command line, a new terminal and say, well, it's bugged. Okay, let's do npm install dash dash safe, React dash router dash DOM. Let's hit Enter. And while that installs, let me create a component here. The good old navbar can't have a website without an app bar. Can you? Alright, so I still RC here, even though we're not going to use it yet. And here in the home, or in the app, brother, let me close the index HTML, the app CSS index CSS, we don't need this. So here in the app. Okay, that's done installing let's import a couple of things from from react router DOM. So we have browser router, you have open router, we have switch and route. Well, my OCD is telling me to sort them alphabetically. So these are from react, router. Dom if I can spell correctly, all right. So for react router Dom to work, or for the router to work, we have to wrap everything here in a router. In the route component, actually, let me name it router, because that makes more sense. So as route, browse the router as router, and here, I'm gonna put our routes, but we need to put a switch and not not the JavaScript switch, but the components which close this and then put our routes here. So the first route will be the home route. And this will be to, not to sorry, path equals slash. And this will have a component which we haven't brought up yet. brunnen yet, of home. So this is the homepage. Let's bring them, let's say here, pages, and let's bring our pages so import home from slash pages slash home. Let me copy this two more times. And here, select those Ctrl D and do login and sign up. And actually, this will be exact. So the exactly this path. So if we add something here, it's not it's not that path, may copy this, space that two more times, and this will be two slash login. And the component will be login. And this will be to slash sign up. And the component will be signed up. Alright, let's save everything. And let's see if this is working. So we get home page here and we've typed slash we get home page. Again, slash login should give us the login page. And it does and slash sign up, gives us the signup page. Now obviously, we want some sort of like navigation bar here with those links. We don't want to type them here each time. So we're going to install material UI right now. So let's do npm install dash dash save at material, dash UI slash core. Now, you can go to material material, dash ui.com, they have really good documentation. And here you can go to actually getting started and it will tell you to install it. And if you want to link it with through HTML, not actually this is the font. And any component you want to use, you go to component API or component demos rather. And in this case, we're going to use the app bar, which is the navbar technically, and yeah, so you can take any of their examples, you click on show the source and you actually get the source code and how to use these numbers. But the way I'm going to Want to use the navbar is different to all their implementations. So I'm actually going to do it manually right now. But there are certain things where I'm going to copy some code, so that I don't waste time. Alright, so material wise has been installed, let's go to nav bar. And here we need to bring it, bring a bar and a couple of other things. So we're gonna have a lot of imports in our file. So I want to put some comments on our imports so that we can navigate them easily. So here I'm gonna do movie stuff, which is material UI. So here are the cons are not constant. Because this is iOS six, by so import our bar. From material, not actually add to material, material, UI slash core slash bar. Now, we could actually up bar like this, now we could actually group all our imports like this, for example, we're going to need now something called two bar and just do this, this would work. But this is not good practice right now, because we're going to new need to do something called tree shaking, where we import each module alone. Plus, the problem with doing stuff like this is that each time you run your app, it's importing the whole framework, and it's gonna make your compiled time a bit slower. So we're actually going to do the practice they actually recommend. So let's do a bar on here slash core slash app bar. And if we were to go back to the documentation page, and expand any of them, you notice that every app bar needs a toolbar inside, and then you have your buttons inside of that. So let's go here. And let's import the toolbar. Let me just copy this actually, and then select this Ctrl D and do two bar, where's the bar actually is the B capital? No, it's just toolbar like that. Okay. So here for our number one, we're gonna need to do return like this up bar, I'm gonna want I want to have it fixed at the top. So let's do position fixed. And by the way, if you're wondering how I know that there is this thing called position, here, you can just on any on any element, you can just scroll down, and you will see the API reference, or you can go to component API and pick your component. And if we would go to our bar here, it will show us that these are all the properties that this component can take and the values that they take. So I'm using right now position. And these are the values you can have. And actually, the default value is fixed. So I shouldn't even type that. Alright, I learned something right now. So I should just leave it like this, because that's the default value. So let's do toolbar. And here, we wanted to actually there's nothing right now, I'm just gonna leave it like that. And I want to put some buttons inside. And for this, I'm going to bring in button from material UI is not actually 100 kilobytes, this import cost extension sometimes doesn't calculate the size properly. Okay, so here, we'll say button. And this has a property color. I'm going to do in I'm going to give it inherit. And, and button actually can take some this is this is a can be a higher order component, and you can pass it a component, a different component, and then pass it the properties of those components. And then you will have that component as a child. So what I'm talking about, you can right now just say button, and say to what is this, this is login. And then let's paste this two more times, and then say home. And then this will be sign up. Let's save as go to our app. Now what we want in our application is that we want the navbar to be at the top and then the navbar never changes. It's only the content of the page that changes. So this navbar right here is not going to go inside the switch it's going to be outside. Of course it's still going to be in the router, but it's going to be right here. See nav bar. Let's actually bring it in, say components. And let's do import nav bar from components slash nav bar. Let's save. Let's go to our up and there we go. We have our nav bar and we have our buttons, but the text is gone, because it's actually behind the navbar. So let's give our, let's make this section that's got the text a container, like a bootstrap container fusion use that before. So let's go in the app, actually, I'm going to go to the global CSS file, app dot CSS, let's do dot container, this class. And I want to give it so I want to give the container a margin top so that the top content doesn't hide behind the nav bar. So actually just do margin. And then here, let's say, so the way margin works, you can, you can give for a numbers, you can give one or which applies to all you can give two values which apply to top and bottom and left and right, and then you can give four, so the first one would be top, and then goes clockwise, right bottom and then left. So here, I'm going to do 84, top, not 2080. And then for for right, I'm going to give the auto for bottom, I'm going to give it zero, and then for left, I'm going to give it auto, so that it it actually stays in the middle of by giving it auto, I'm going to give it a max width of 1200 pixels, so that it's actually kind of pushed to the middle. Alright, so let's save that. But we need to give this class to something. Think, what do I surround? Where do I surround, I think I'm gonna surround the whole thing. So let's copy the cut that and then do dot container. And then put our stuff here. Let's look here. All right, cool. Actually, the navbar shouldn't be in the container. So the navbar should be outside, like this. All right. But our buttons right now don't do anything. So let's go to the navbar. Here. Like I said earlier, we can pass a component and here we need the link component from react router DOM, the import link from react dash router ashdon. And here we're using tree shaking as well. So we're importing only that component. So here, let's take the link. Let's do, let's write in all of these fields. And let's do component equals link. And here, we can actually pass the properties of the component link, and it will be under the button. In a way, it's like actually putting it here, but it looks cleaner. So here, let's do so the link needs a two property. And for login, it's going to be two slash login. For home, it's gonna be to slash to just slash. And for sign up, it's going to be to slash sign up. So we save, and then we go to our app. And there we go. So click on our buttons. Actually, it takes us to those pages. Cool. Let's bring these buttons to the middle. Um, how do we let's give this toolbar a class name of nav dash container. eyes go to our CSS, CSS, app CSS and do nav dash container which is going to have margin auto. Let's save save everything. Let's go and there we go. Buttons are in the middle. Cool. Alright, so our application so far has no content. I mean, there's no markup, our pages are empty. So let's start working on the homepage. Let's start showing, let's fetch the screams that we have and show them here. Alright, but before we do that, let me go to the material UI documentation. I show you something. So first thing is I want to implement a theme. Alright, where is it? utils. No, no customization? Yeah, themes. Okay, so we don't have to necessarily, you know, create a theme but I want to create one. You can do so many things with the theme. You can set a color scheme you can have like, font, your font size, your global styles, all this stuff. So I'm going to create the theme and just set some colors. And because I don't like this blue, alright, so to do that, let's go to our app j s. So here, we need to bring in two things. Go right here and do import Mui theme provider from to add material dash UI slash core slash movie, not actually stylish life styles slash Mui theme provider. Next thing is the Create theme function. So import, create theme, oops theme from at material UI slash course lash styles slash create. Actually, it's create Mui theme, I may copy that and put it here. Alright, so to create the theme, we just need to do const theme equals and we just call that function create Mui theme. And here we pass it an object with some options. Oops. So here, we pass it this object with options. And for me, I just want to have like a color palette theme. If you want to create yours, you can go to hair color. And you can take any of these colors and you can scroll down and there's a color tool here, pick your colors, you can just have the primary colors, or you can have multiple shades. I've already got mine, I started in this text file, I'm just gonna copy it, you can take the time to create yours, I'm just gonna paste my hair. And I'll just save. Actually, one more thing we need to provide the more with the provider, I'm just going to cut all of this and do Mui theme provider. And it has a property of theme. And it's just theme because we named this variable theme. And close that and let me paste everything back in it. Alright, so now everything that's got the color primary will have this main and everything that's got the color, secondary will have this main. And this contrast text is basically the color of the text that's on this element. And for me both colors, they have to have white text on them, which stands out the most. So let's go to our app. And there we go, the color has changed to this beautiful blue that I chose. Alright, so next thing, let's let's start showing the start showing the screens here. So to do that, let's go to so the home. In the home, what I want to do is I want to have a section here on the left four screens, and I want to have a section on the right for the profile. And I want to have like, if you've used bootstrap before, you're going to have a core row. And inside of that we have columns, I want a column on the left, that's of the width eight out of 12. And the right one would be four. And for that, we're going to use the grid system. So the grid is basically there. So if we expand this, you just bring in grid, which is right here from material UI, and you just put the container with the grid and you add this container property, and then the elements will have this item property. So let's just do that here in the home, I'm gonna, I'm going to remove this stuff. And I'm gonna put grid container. Close this on the inside of here, I'm going to put grid item. And this will have a property small of eight, which means of the small screens gonna have a width of eight an x s, which is extra small of 12. So in really small screens, it's gonna take take the full width, but I'm gonna put the text saying content. And let me copy this paste. And this will be for an extra small screens is going to be 12 as well. And this is going to be profile profile like this. Let's save, we need to bring in grid of course, or grid from material UI slash go slash that just grabbed the just grid like this with save. Let's go back to our app. And there we go. We have this which has if we inspect we'll have summit bring this let me put them side by side if you can see her takes on the full width. Right now. Actually, I want to edit it because this is right now leaving no space between them. And as you can see her you can have this property spacing. Okay, let me look at the example the proper example. So here Yeah, the second example. So if we look here, it's got this. Where is it? Yeah, here you give the value of the spacing okay, right here. So grid spacing, and then you give a number. So for me, I want the number 16. So here, I'm going to say, spacing equals 16. And a save. Let's go back. Right now if we inspect, you're going to see that this would have a padding. Yeah, there we go. So it's got a padding, which is going to push the content a little bit to the middle. So there would be space between our element elements. Alright, so let's go back to our app. So here in home, we have our, our grid here that says content. But here, we content is not enough, obviously, we want to put our our screams. So for this, we need to fetch them from our server. So in component that mount, I'm going to send a request to our server. And for that, actually, we're going to use axios. So let's install that, open up a terminal and say NPM, install dash dash save axios. And let me go to my Firebase dashboard and grab the, the endpoint, or the base URL of our API, I go to the project to functions. And if you're just doing the React bit, this is going to be in the video description of part 14, or in a comment in the first video, or in both. Alright, so I'll copy that. And if you've done the backend, of course, you know what to do. And so in react, the way we set up our base URL, instead of using it everywhere, we can just go to the package JSON. And here at the bottom, we can add a property called proxy. And let's paste this and without the last slash, because I want to add on each request, because it makes more sense like that. Alright, so axios is installed. So let's bring it in. So import axios from axios. And here in the component did mount we can do axios. The get, and here we send a request to slash screams. And if you remember, or if you've seen the backend, okay, let me send this request. This is the type of data oops, it's a get request, and remove the body. So this is the type of data that we're gonna get. This is one screen, it's gonna have this these properties. So here to slash screens, because this returns a promise. So then result, we want to do we want to store these screams in the component state. So let's initialize that. So state state equals an object and it's got screams, and that's going to have an initial value of naught. So here, if we get a result successfully, we do this dot set state. And in the state, we set the screams to because this is axios. We don't just say response. The data is actually stored in a key called data inside the responsibility rest data. And let's handle any potential errors. If there's any error with just console log, error. Cool. Alright, so let's actually show our screams. Because right now we're just fetching them. And when we get them, let's, you know, stinkers, let's just console, log them and see res dot data. Cool. All right. So here, content will get want to put like a variable here, and let's call it haven't created it yet, but let's just call it because these are the recent posts, excuse me, say recent screams, mock up. Let's create that. So here, let's say let recent screams mock up equal. And what we want to do here is we want to check if we have screams in the state. If the screens in the state are still no, that means are still no, that means we're still loading the most still fetching them from the server there. The request hasn't got a response yet. So we can use this in a ternary operator, we can do this dot State DOT screams as a condition. That means if it's, if it's not, no, that means we've got the data. So let's actually show the data. So what we did here, let's do parentheses, and let's do this dot State DOT screams. So if it's true, that means it's got some value in it, it's not not. So this set of screens dot map, and for each screen, let's For now, let's for now returns return a paragraph and in that paragraph, we put the opening curly braces. And remember, this is the data we get that show the body. So let's go back. So for each screen that shows screen, dot body, and as you see right now we have only two screens. Alright, so for each one we show that else if it's still no, then we'll just show a text that says loading dot, dot, dot. All right, and we put that markup variable there. And we save, call it compile successfully, we go to our app. And it says loading because inquire, status 404. Or there's another problem here for material materially Why? Because of the topography, are we even using topography, we need to add this to our theme. I've seen this error before. So we got up to our theme, we add this property at the bottom. typography use next variance and that error should be gone. But we're still not getting our screams because we get error 404 localhost 3000 slash screams is not found. Maybe we need to rerun our though server when we change the proxy, let's let me do that. So stop it and run it again. Alright, so yeah, we had to restart our server. And there we go, we get the text for the body text of our screams. For each screen, we get the body text. So the first one says hello, user. And the second one says something. So there we go, we got them cool. Let's actually show them in a better way we show who posted them and when and stuff like this. Now for this, we're gonna need to have to create a component. Well, where are we in home, let me close this. And this. So here in the home, we need to actually use a component that's specifically made to show us details for screens. So let's create a component, let's say here screen. For screen, we pass, we actually pass a property called screen, which is going to be the screen. And let's close this, let's import it and then create it. So import scream from and then we're going to put it in. So go back one level and go to components to slash scream. So let's create this. So here let's do new file, scream. Of course, this is a component. So it's, it's Pascal cased. So the first first letter is a capital. So as to RC e tab, remove this export. Now for this here, like I know we're going to do some styling later. So let's let me show you something in the material UI material you why they prefer to use this CSS, JS type of styling where where you actually write a write an object, a JavaScript object, and then use a higher order component to apply those, those styles and make them into classes and then use them. If you know, if you want to see an example of that, let's go to for example, buttons. And as you see here, they import this with styles component or higher order component. And then they create a styles object. And it's optional. If you want to bring in the theme, the global theme that you created in your app. js, you can do that. So any stylings that are kind of shared between components, you actually write them in the theme in app js, and then get the theme and then use them there. So you don't have to repeat yourself in multiple components. So it's like this Your brain with styles, you create your styles object, and then you export your component with this higher order component with styles. So you pass it that styles and then you pass it your component. And then this will create an object called classes in the properties of this component. And then you get the classes and then you use it like this. So for each component, you say class name equals classes dot button, and now these styles in the button will be applied to this button right here. So let's let's implement that. Okay, so let's, for now, I'm just gonna put like some random style, just to apply this method first. So here we will have styles. And here we're gonna have a card. So let's put here for the card, let's just say display. Flex, which I don't think changes anything. Let's bring that with styles, but doesn't change anything. For this example. Of course, in many cases it does. So let's do import with styles. From Material art material, UI slash core slash style slash with styles. And then we go here at the bottom, we do export defaults with styles, and then open parentheses and pass the Stiles constant, this one, close parenthesis, open parentheses, and then pass our component scream. Now, this will give us access to a variable classes and the properties. So inside, actually inside the render, we can D structure this variable, we can say const. Like this, when classes equals this dot props. And of course, this is the this is the equivalent of saying const classes equals this dot, props, dot classes, this call destructuring. So anyway, so now we have classes, we can actually access them. But let's create the markup of our of our screen. And each of our screams is going to be a card. So let's look at the card element. So if we go to cards, component demos, cards, this is the card This is one of my favorite elements in material design, it's this card actually has these the side shadow that looks it's kind of like on top of the background, like kind of extruded a bit. So this is what we're going to use, we're going to have an image, but it's going to be on the left. So this is the kind of the kind of structure that we're having, we're going to have a card with a card media, let's take some of these imports. So namely, these four right here are these five. let's paste them up here to see movie stuff. I spaced these, but we're not gonna need actions or action area. To do this. Let's do caught on like this card. And inside of card, we're gonna first thing was gonna, we're gonna have the image. So card media. And this will have an image property. And this will be the image of the few image of the post of the screen, it's going to be in a variable called user image. So let's do image equals scream. Or actually, let's just say user image, let's extract all those, those properties. So let's do const. Or actually, it's in the props as well. So the scream is in the props, this remember guys, the scream that we pass here, excuse me, as in the props. so here we can, we can further destructure properties from property from an object inside of props by doing this, so scream, like this. And then we do colon, and then we do another object here, and then we extract properties from inside the screen. So what we need is, we need the body. We need created art. Use image, we need the use handle. I think this is all we need for now, maybe the scream ID. Well, let's get all of them the light count, and then the comment, count. Alright, so this will extract them and we're going to access them like this. So Alright, so the we have the image. So it's there is the title property for the card, mid card media, let's say profile, profile image. If I can spell. Alright, so after card media, we're going to have our content. But I want to correlate or just let's just put the card content for now, let's not worry about the styling for now. Let's look at what it looks like and then style it. So here we're going to have the handle of the user. So let's we're going to use this thing called typography. In materially why it's preferable whenever you have some sort of text that you want to show you want to use this typography object. so here if we go to component demos, or actually it's up here. Yep, in the style, typography, typography is any type of text you have in your app used Pog, Rafi and then you give it a different variant, which is going to give it a different size and styling. So for this, we're going to use typography. And by the way, whenever you're confused with these objects, you just are with these components. You can check them the documentation and the API component API. And you can as well when you put they have types so when you put a component you can press Control space in VS code, and you See all the properties or actually have an important that so we can't see any. Okay, so let's import typography from material, UI slash core slash typography. Now, if I press Control space, there we go, we get all the properties that can exist on this. And then if we type, let's say one of them, which is variant, and we do equal, and then we can get as well more properties here. For this, we're going to use the head of five want it to be a slightly big. And let's close this and let's say the value will be used to handle. And then after this, we want to show when this was posted, so as to typography, variant, certain body board, give body to Okay, body to, and let's give this a color of text secondary, which makes it a bit gray, because we don't want it to distract from the content is just like metadata. So this will be the created art. Now we want the actual body of the, of the of the screen. So type biography, variant. body, body one, let's give it body one. Let's see what this looks like. Alright, so this is the screen. Alright, let's save. And let's save here as well. compiling, it complains that we didn't use those variables. Let's look at our app. Alright, so there we go, we get our card. But there's the color of the card and the color of the background are kind of the same. So let's change that. Let's go to App CSS, and the global CSS and actually here, the body want to give it some sort of background color. Give it like very light gray, RGB, going to give it to 45 to 45 to 45. Let's save. Cool, so we have not great and these cards are white. So they stand out. Let's give this some kind of like margin. And this should be a link to the user's page. Clear screen. Actually, this we want to give it the component. Link. And the to oops, do not go to will be actually a template string. So curly braces backticks. And is to slash users. We haven't created this page yet. But let's just do slash users and then pass user handle to import link, import link from react router, Dom slash link. Alright, let's check our app. Oh, this is underlined and the color is still the same. Let's fix that. So here let's give the anchor tag globally. Let's give it no text decoration. So text dash decoration, oops, decoration. None. And to change the color, it's good to scream. Where are we we're here. So let's change the color which is going to give it the color primary to get the our blue color. Let's save everything. Cool. So there's not underlining and the color is blue. We click on it. And it takes us to slash user slash Johnny. Cool. But we don't see that image actually, because for some reason it has zero width. Can we inspect this and try to fix this. So Oh, it's it's Oh, it's in a div. That's, that's interesting. Let's just actually edit some styling here. So starting with the card, I wanted to have a margin bottom margin bottom, so that we'll have some space between the cards. Give it 20. And I think that's it for the card. Let's edit. Let's give this a class of classes dot details. Which we don't always say content because it's the card content. And let's give the card itself class name. classes. Remember, we have this classes object. So classes dot card. Oh, we actually didn't give it earlier. And where's the image? Do I give the image a class? Yes, I think so. Classes class name equals classes dot image. We go here, let's give image some styling. Let's give it a minimum width of 200. And, yeah, that's it. Let's style the content. So content. Um, what do we want to do, actually? Okay, let's give it some padding, because it's too close to the edges. Okay, feel like padding of 25. Let's see what it looks like. Alright, so we got the image now. But I think the image is kind of being stretched. Okay, I don't like this way, let's do object fit. No, cover the same. But I think if I were to make this div longer, it will stretch this because we let's let's give an object fit cover because that's a good property to give your images so that they don't get stretched by the change the changes of the dimensions of the image. Are let's save this. And let's look at this. Alright, slick and much better. Of course, we need to format this because we don't want to show this ISO time string. In the last video, we started working on the homepage, we created a screen component. And now we're showing our recent screens on the homepage. Now, I've went ahead and added one more screen and some likes and comments, which we can't see right now because we're not displaying that data. So. But I noticed something, if you open up the console window, we have a couple of errors that we need a couple of warnings that we need to fix. By the way, this is the data that we got back from our API endpoint from our request. We printed it right here, here, but I'm going to remove the print because we don't need to have the data. Let's look at these errors. So first one is react router Dom apparently it doesn't like it when we import link separately. So let's fix that. So here in the screen, here, so let's do structure link from the entire library. I think we're using it in the home as well. No. Yeah, in the navbar, we're using a navbar. So here, let's remove the slash link and just do like this. And by the way, my server still run in my development server, if yours is not just run npm install, I'm going to close this window, I'm going to save all files. Let's go back to our console window, that error is gone. And here it says each, each child in a list should have a unique key, or this is a react thing. I think it's in the home. Yeah, here. Whenever we are looping through an array, and we're showing some data, each child has to have a unique key property. So let's pass this a key property. And we know that our screams they have the scream ID property which is unique. So let's do scream dot scream, ID. And that error should be gone when we save. And it is apparently I gave some class a class instead of class name cinna card content. So that's in scream. Yeah, right here. So class name instead of class, and all the errors should be gone. And we only get these warnings that we're not using these values. Cool. Alright, so I want to format this, like you see in Facebook and Twitter whenever someone posts something you see like five minutes ago, or like two days ago or whatever. And for this, I'm going to use a library called dangerous Now we could use moment moment is great, but moment has like loads of extra functionality that we're not going to use. And it's adds like more than 50 kilobytes to our bundle size. So I'm just gonna use an old lightweight alternative code they they j s as my voice is cracking. So npm install dash dash save day j s. And as it's installing, I'm actually gonna bring it in here. Let's do import de j s from they j s and not the stage s. So if you forget to go To the documentation, you'll see it's it follows the same convert or like same format that you would use the moment you just call the class, or Lamine the library, and then you pass it the date, like here, and then you do dot format, and you format it like you want. But for this one, we don't need that format we need. Actually, we need a functionality that comes from a plugin, where's the plug in list right here. So I'm going to search for from now Yeah, so it's this from now thing, we want to show the date like this, this relative time plugin, so we need to bring this plugin just like this. So let's copy this. Let's go here to import relative time from there. And the way they just works is that we need to call this extend function to actually add this plugin. So at the start of our code we need to do they are not in the class in the render method. So here we say they j s dot extend, and we pass it our plugin so relative time. And here where the date is right here, we cut this created that we say day j, s, and then we pass it the creator that date, and then we do dot from now, simple as that we save, go to our app, I close this console, go, we get this was posted an hour ago, this was posted 17 hour, hours ago, and this was posted 19 hours ago. Cool. So we get the relative time thing. Now we could keep working on the buttons that are on the card, on the screen cards, like Like buttons, the comment and the expand and the delete button. But most of these buttons actually depend on our authentication state. So for example, the like button, if you are not logged in, it will, if you click it, it will direct you to the login page if you are logged in. And if your legs if you have like the screen, it will be a full heart. And if you haven't, it would be like an empty, just outline heart. Now, because all this functionality depends on authentication, that means let's actually work on authentication, and then come back to continue with the screen cards. So let's actually implement the login page, because there's nothing there. Alright, so let's go to login. And here, we're going to use text fields. So let's go to the movie Doc, let me close this. Go to component demos, we're going to use something called text field. And it's this thing right here. Well, there's multiple implementation, but we just need a simple text field. So as you see, you just bring in text field. And, and yeah, you just put text field inside of your form, which form which is a standard HTML form. And you put these properties inside of it. Alright, so let's go to our login. Let's first implement the width style or styles thing, because we're going to need later we're going to need to bring in some global styles and access the global theme. So let's do import with styles from material UI. Slash cause slash styles, slash with styles. All right, let's create a styles object for now is going to be empty. Let's do export default, with styles, path, pass the styles. And then for the second thing, pass login. Actually, login should be lowercase login. Again, and here we're going to have inside the render actually, we'll do const as take our classes, or we have none right now. But we will in a moment. So let's do equals this dot props with the destructor. From props, let's actually use prop types. It's a good practice to use prop types, which is a way that a built in method in react for type checking. It minimizes like the potential errors that you can get in your application. So as to import prop types from prop types. And here we do login dot prop types camel case. So the first P is lower case equals an object. And here, right now we only have this classes. So we'll say classes. And this will be an object. So there's two prop types. Remember this prop types, capital p.object.is required because it is required. And now we're going to have our form here. But what I want to do is here in the login page, I want the form to be in the middle. So not to take up the whole space. So what I'm going to do, maybe there's a better way of doing that, but for now, I'm just gonna have a grid, and then have three columns, and then have the one in the middle have a hold our form. So let's bring in grid, let's do here, movie stuff. That's important grid from material, dash UI slash go slash grid. Yeah, that's all we need are now, here, let's remove this div, and let's do return grid, this is going to be the container. And let's give it a class name. Even though we haven't created it yet, say classes dot, I know this is not the form, it's the form container, but I'm just gonna call it form for now. Let's do three grid items. So grid item, and I'm gonna give this a value of small for small, they will take up the whole width. And let me copy this and paste it two more times. And then here, this one is gonna is gonna have a, it's gonna have content, so it's gonna have a closing tag, like this. And for now, here, let's just say I don't know, you're here, we need this form, class, say, form. And what the form is gonna, well, I know we're gonna have a text align, we might add some stuff more later, I still text align center, on the everything to be aligned to the center, like the the title of the page, and we're gonna have an icon as well. Let's save this for now. And let's look at it. So we get yo and it's in the middle. And if we inspect this face, if you see we have three divs. And they share exactly, like, what's cool about material UI is I don't have to say that this is this has a width of four and four and four. By default, if you put three elements, and you don't give any default, any width, value, I mean, any like column width value, it will automatically split the, by the number of you have the children you have. So if you have four grid items, it's going to give them 25% each, if you have five, it's going to give them 20, etc, right? And I was given them 33%. But the problem with these divs is that they don't have any padding, we need some spacing, to push, or do we actually we don't, it's just like, because we're not going to have other divs from this side. And this side, I'm not gonna have any content from the left and right, so let's leave it like that. Let's so here at the top, I want to have the monkey image thing. Let's actually bring it from the public folder. So let's copy this icon. png let's create a folder here called images. And let's paste it. Close it as bring it in. Let's do import. What do we call it up icon? Doesn't matter. We can call it anything. We go back on level you go into images. And what does that icon dot dot png. Cool. Here let's put image the source. What is that source? tab CRD equals? What is it up? I can't I already forgot what I call it. Yeah, icon. And yeah, let's give it an alternative property because react warns us if we don't let's just say I don't know, monkey image. We'll just monkey. Close this. And under here, I'm going to have a title that was that says typography. Actually, I noticed something here that I made a mistake here. I forgot to fix. I imported typography and typography. And as well here I use typography instead of typography and one of them Yeah, this one. Space this here, save. Cool. All right here let's bring in typography. typography from from material, cash UI slash core slash. typography. Cool. All right here we're gonna have our title. So we're gonna do typography and by variant of a variant of video How to one or how to to, as to how to one, it's good for search engine optimization to have a header one in each page. And let's give this a class name of classes.is called this page title. This is gonna say, oops, it's gonna say login and Let's just look at it right now. Oh, it's massive, she's heard it too. Okay, heard it is better, let's have some padding or margin between this monkey image between I wanted to like kind of have its own space. So let's give this a class name of classes dot image. Let's do image, oops, image and margin, give this. So I want to give it 20 on the top, although on the right, and then 20 at the bottom, and then auto on the right on the left, call, there's some space between it and the title. And let's create our form now. So under the typography, here, let's do form. I'm going to give this no validate, because we're going to have an email here. And by default, html5 will try to validate the email field. And let's give it a name on submit this dot handle submit, we haven't created yet. created, handle, handle, submit, we're gonna make it an arrow function so that we don't have to bind to it. And it's gonna take an event. And here, we're gonna just console log on a high for now. And here, we're gonna have our text fields. So we're bringing in textfield, we have an a spring in has to import text field from, to material UI slash core slash text field. Now if we type text field, you can do Ctrl Space to see older the stuff you can add to it, I already know I'm going to use, I'm going to give it an ID of email, and name of email, which we're going to use later for when we are handling the change, a type of email, which is, to be honest, not that important, but it's just good practice, let's just add a label. The label is just gonna say, email. This is what is written on it before we type anything. Gonna give it a class name of classes dot txt field. This is our Java JavaScript object. So stick to like, we should stick to camel case, variable names. I'm going to come here gonna give this a value. Actually, we haven't declared our state yet. You're gonna give us a value of this dot State DOT, what is this the email, the email. And here, I'm going to, there's two. Well, there's two main ways of handling forms in react. One is the references where you create references for your input fields. And then you get the values that references and the second one is the more popular one called controlled component, which is using the state. I mean, they're both the same, I just prefer the controlled component one, so I'm going to use it. Actually, maybe they're not the same. Maybe there's different applications for different different, you know, scenarios. But I prefer to use the controlled component one, because we can use the React dev tools and check out to the state to make sure that everything is working fine. So let's do this dot state equals we're going to have an email and a password because this is our login form. We're going to initialize them as empty strings. Actually, we're also going to have a loading property, which is false by default. This is when when you press the login button, I wanted to show like a spinner as it's requesting stuff from the server because we're using Cloud Functions. Well, in general, it's a good practice by using Cloud Functions. Sometimes the first execution is kind of slow. It's called a cold start. So having a spinner actually gives makes the user gives the illusion of the app being more responsive and it actually doesn't. It seems like the time it takes loading is less when you see a spinner. Okay, so we're gonna have an errors array in case any errors happen or invalidating the form. Okay, so we're here. And what do we what else? Yeah, on change, which we haven't created yet. There's gonna be this dot handle, change. Let's create that. So we could actually do a handle change and pass this the name of the field. But since we already have a name here, we can do it in a, in a more generic way, by doing handle, change, equals, so I have an event. And here, we're going to say, whatever put the handle submit outside the class. All right, so handle change is going to take an event, and this event will have because we're here, well, or any on any other textfield, this event will have a target property. And if we're on this text field, this target will be this text field or the input actually in the HTML. And the input has a couple of things. One of them is the name, because we gave it here the name and then one of them is the value because it's what's written in it, or what's in the state. So what we can do here, we can do this dot set state, we want to set the value of the input to the value of the, to the to the to its corresponding value on the state. So we can say, this dot state, and we want to set so this is generic, it's going to take an event dot target, dot name, so if it's if it's the email input, it's gonna have email, if it's the password input, which we haven't created yet. It's gonna be password. and the value of this is going to be event dot target, dot value. All right, so this would work for both of them. And yeah, okay, so we have this on change. And I'm going to add this full width property, which is going to let this textfield take the full width of its containing div, I'm going to close like this. And by the way, if you're wondering how I know this full width thing, or anything else, you could just go to here, textfield, go at the bottom to the API reference, click on the text field here. And you can see all the all the properties that you can actually use this, there's tons of different stuff that you can use. To make the experience better, we're gonna use a couple more later. But for now, let's, let's copy this text input or text field rather. And paste it. And the second one will have the idea of password was just actually select Email and then Ctrl D, three times or four times or three times rather, and the password. So yeah, I just password name is password type his password so that we don't see when we're typing. And the label is password with capital P. class name is that textfield values, this dot State DOT password on change is the same and, and for width as well. Alright, so now we need a button to submit this form. And for this, we're actually going to bring in the material UI button. So as to import import button from material UI slash core slash button. button. Alright, so where are we we are here. So here we say button. of type Submit. And I'm going to give it a variant. You can go to the material y, doc and go to button, not the API the demo. Pick any variant you want, you can have the this one, I don't know what you call this actually was the variant of this, this is the default, maybe Yeah, it's the default. But this is called contained. So I like the content one, it has the whole color, and it has this drop shadow, it looks cool. Alright, so let's give a variant of content contained the color of primary and the class name of classes dot button. And we need to create all these styles actually. So okay, let's close this. And let's go here. Let's do what do we need to style we need to style the the page title. So page title, I want to have like some margin for the page title. So let's give it margin. Still the same for same for the image. Save, let's look at it. All right. Oh, this looks weird. Okay, so we have our inputs, but there's too much space between the login and the images. Just reduce this to Ctrl D reduced this to 10. Let's look at, okay, this is better. Actually, I want the inputs as well to have some margin on the top and the bottom. So let's style that. Let's do text field. Yeah, thanks to the old text field. So I need to give the text field the margin as well. Give it give it the same as the title. Let's look at it. Alright, cool. I don't know what's wrong with the button. Why is it doing that? Oh, actually, what am I saying? Of course, I know what's wrong with the button? Because the button needs some text inside of it. Of course. Login. Yeah, there we go. Alright, so text field. And what do we do now? We need some margin between the button and the input. So let's do button margin, or just margin top? margin top because just say 20, you can do a number. And yeah, this is it. All right. Let's test this out. email@gmail.com? Oh, of course, we didn't write the handle submit, what am I saying? Okay, we need first to prevent default behavior. Because of course, we don't want to show this information here. And we don't want to reload the page. So let's do let's do event, dot prevent default. And here, what we want to do is we want to send a request to our server, and then show any errors or, or if it's successful redirect to the homepage. So we're going to use axios. So let's bring it URL. So let's do import axios, from axios. And here, what we need to do, well, actually, we need to implement the loading thing as well. So once the this so the form is submitted, we do this dot set state. Two, and then we give loading, true. And then once everything is done, we're gonna set it back to false. And now we're going to do axios dot post. And it's gonna be at slash login. And by the way, if you if you haven't, if you don't know, or if you haven't forgot, or if you haven't seen the part for the API, this is how the login works. You send an email and a password. And if it's wrong, you like, if the email is wrong, you get an error. Actually, if anything is wrong, get the general error that wrong credentials, please try again. And if if the email is empty, you get an error just for the email. So we're going to use this errors object and give just that input the error that corresponds to it. And if it's, it's like, if it's correct, we get a token. When we get Oh, user, not users. Yeah, so if it's correct, we get a token, of course, an OK response, which will allow us to redirect to our homepage. So here, so post that login, let's get the data so const user user data, let's call it and it's going to be an object. And this will be will have a an email, this will be this dot state. So remember, we bound those values to our state, this dot State DOT email, and the password will be this dot State DOT password. And then we pass user data here, I mean, we could put this object here but it looks cleaner like this. And this returns a promise. So then if we get a result so if we get here that means we're successful. So let's actually console log our result. Result Oh, this is axial. So with the data will be in resultant data. So first successful we want to redirect so want to do all a set the loading to false actually, first, let's do this dot set state. Loading to false. And then here we do this stop props dot history dot push and then This is a, this is a method we use in react to, to push state URL and then we go to it, or a path. So here we push slash, which is the homepage. So this should redirect us to the home page. And but if we have any problem if we have any errors, so we do catch error, and here, we need to set the errors of our form. So what we need to do is this dot set state. And we want to give the errors, the value of error dot response dot data. And we want to, actually, this is errors. And we want to set the loading to false. Right now the loading is not being used by anything. Let's get the loading from from the state. That's actually good errors as well. So we can display them. So let's get errors. And loading from state. This dot state is in the structure and again, and here for the input, we're gonna use something called helper text. So if you if you click on an input, actually not here, so if we go to text field, yeah, this is the helper text, this text right here, and you can use it to display arrows, or you can use it to display hints. We're going to use it to display errors if there's any. So here what we need to do, we need to say, helper, oops, helper text equals, and this will be because this is the email this will be errors dot email. And we don't have to worry about if there is nothing errors, if there is no emails, if email property is just not going to show anything. And here as well, we need to have an error property, which sets the field to be read. So here we say error. And the way we determine whether we have an error or not, is because we this is the email we say errors dot email, and use a ternary operator. So that means if we do have this key, that means there's an error in the email because we have received an email key in the errors array. object. So we say true, else. It's false. There's no error. Otherwise, if we don't have this, so let's copy this and give it to the password as well. So here, let's do errors dot password, Ctrl D, and the password like this. So now when we get our response, and we get errors like this, or is it errors like this? Let me cause an error to happen. Actually, no, I mean, how this empty. We can have this email and we can show it in the helper text. All right, so let's save. So let's leave them empty. And we click Login. Oops, it says, type error cannot find data. Oh, it's because I misspelled response. response. All right, so we sent there we go, we get our errors and put in the helper text and the input is invalidated. And if I would put an email here, so let's say I don't know, like something at something. Whenever I type something random, it's like sad what the hell. Alright, so login, that error is gone. And if I give like a random password, Oh, actually, we need to show if the credentials are wrong, we need to show some error right here. So So here, I show it under the button, or not actually show on top of the button. And let's say here, we do like a conditional errors dot, because if we have wrong credentials, we get we get an error called general. So let's check for that error lead to errors dot general. So if it's the case, so and and if we have errors dot general then render this understood typography variant, give this body to this we'll have a class name. Because we want to change the style of this classes dot custom error, I'm going to call it and here we're going to have the value of that general key. So we do errors. dot Gen. And here let's, let's get discus. Let's style this. Let's Okay, so custom error. Let's give it a, like a red color color. Red like this. And let's give it like a smaller font size, font size. Let's give it like naught point eight, run. Yeah, I think that's it. Okay, let's try some wrong email. And some wrong password. Cool. We got wrong credentials, please try again. Let's give it some margin. So it's not too close to the to the input. So let's give it margin top, say 10 pixels, like this, or just 10 like this. Oh, I mean, I have to put something. Yeah, there we go. Much better. Let's as well add some text here that says, if you don't have an account, go to sign up. And with a link that redirects to sign up. Let's go here under the button. Let's say give us put a small and say don't have an account. Sign up. And then put a link here to slash sign up. This is the React router Dom link. And it will say here. So this will the word here will be a link. So let's go and bring in link. Import link. Whoops link from react router. Dom. All right. Oh, actually, as well, I want to do something I want when we click Oh, this is not cool. So I want when we click on login, I want to show a spinner inside of the inside of the login button. And I want to make it this disabled. So we don't we can't click it again. Alright, let's make this actually come down. Like under the button. Let's just add a line break. So. Yep. All right. It's cool. So if you click here, it goes to the signup page, which has nothing right now. Alright. By the way, this looks purple because it's visited you can change the color of that. I'll add the login the spinner thing you can go here. Yeah, progress is progress thing, we can add the indeterminate progress one. So which is just what is it? It's circular progress, we can copy this. Let's go here. On the movie stuff. Let's bring it in. And here it's gonna be inside the login button. So here let's do if loading. So if we're loading we do we return this circular progress thing. And let's do a class name. Because it's gonna need some styling classes dot progress. Now, the way I want to do it, I want to have it in the center of the button. So I'm going to do to the button is okay there we give class progress. Okay. So so the button will have a position of relative so that we can give the spinner a position of absolute so that we can put it in the middle. So position. position. Absolute. All right. Okay, we've got a spinner for like a fraction of a second sexually. Why is it being too fast on it to be slow. So let's give the wrong password lesson as being too fast, but all spinner is a bit too big. To give it can take actually a size property. Just just a number. Let's give it a size of 20 or 3030s. Okay. I don't know I can't see it right now. But we get a spinner back. Oh, actually, it's, it's in the middle. Let's go. That's fine. What do we do? Actually, I want to I want to make the button disabled when we're logged in We are loading. So we will do disabled, which is a Boolean, and we just pass that loading. So if it's loading, it's disabled, if not, it's not disabled. So let's refresh, hit the login button, see becomes like disabled for a second. Cool. And if we have the correct credentials, so email us@gmail.com, we get 123456, the password, cool, we're redirected the homepage. And, of course, we're not setting the state to be authenticated or anything, we're just redirecting right now. So in this video, we're gonna create the signup form. But before I get to that, I want to recommend you guys download the React developer tools, Chrome extension, I'm assuming you're using Chrome if not find an equivalent in your browser, it's really helpful. If I open up my developer tools, put them side by side, open up the React tab, you can see we can drill in all our components and see what's happening, what components we have, what state they hold. For example, if we click on our login component, you see the state right here. And if we type stuff updates, you see update live, if we get some errors, you can see our errors. Here, you can see the loading Boolean, you can even trigger change values and see how your front end reacts to it, you see, I can put the loading and I can see that animation. Alright, so it's just that one, one thing I recommend you guys do. Alright, let's actually create the signup form, it's actually gonna be so similar to the login form. So let's go to login, copy everything from here, and then go to sign up. Let me close the terminal, paste everything. And we're going to change a couple of things. So first thing, first thing, these styles are shared between the two components, so we can make them global. So let's copy everything here. Let's go to App j s. And here, we can paste them in our theme. And we can get them by making the styles actually a function that takes the theme object and returns the following. And here, we can just spread the theme. And we will have access to everything that's in the global theme. So let's do the same for login actually. So let's go to login. And here instead of styles, we'll just do styles like this. And we're going to have the theme in there. Cool. So now here, let's change a couple things. So the class is sign up. And here we have an email and password. And we have a Confirm Password. And we have a handle as well. Alright, so that's the same, this is the same here, we have new user data. And we also send the Confirm Password. This dot State DOT Confirm Password, and the handle as well. So this dot State DOT handle. All right, so here we send an axios request post request to slash sign up. And we send the new user data. One thing I forgot though, when we get the token, in res dot data dot token, we need to actually store it in local storage so that if our application somewhere refreshes the page or closes the browser opens it again will have access to the token locally. So we can do local storage dot set item. I'm going to call this FB for Firebase ID token like this. And the value will be a template string bearer space. And here we do dollar sign curly braces res dot data dot token. And we need to do the same for login actually. Let's copy this one line and go to login. And here when we get a response, we do the same. Alright, so let's go back to sign up. Okay, so we set the state to load loading to false we push to the homepage, everything is the same, we get classes. And here the title will be sign up. Excuse me. Here the first text field is the same as the email the second one is the password is the same. And here we need two more text fields. So let's copy this and paste it. The third one will have the ID of Confirm Password we're not really using these IDs but it's if you want to use them to style or anything you can or to do anything else. The name will be confirmed password like this and the type will be password the same the label will be confirmed password like this. Class Name is the same the error will be error dot Confirm Password. Same thing here and here. Starts data Confirm Password and handle changes the same. The third one, the fourth one, rather will be handled. The type is text, the name is handle the ID, the label is handle with a capital H. And here the errors errors dot handle. So we can do Ctrl, D twice and right handle the rest of the same. And here the button should say sign up. And here we should say, already have an account on which should say login here. And this will redirect to slash login. And this will be let's do control D here as well. So you can we can change both of these and do sign up dot prop types equals classes is an object and is required. Alright, I think this should be fun. So let's save all files. I've already got the server running the dev server up and running. So if we go to our app, we go to sign up, we see this phone call, we send we got our errors. And we actually if we actually like do new three, et CIE email.com. And the password will be 123456. And we let's do a handle that exists, it's going to check you will see that let's do a new three with sign up. Cool, so works, redirects, everything is fine. These are just the requests that we send, and we're not valid. So that's fine, we go to application for local local storage, we find that our token is now stored. Alright, that's cool. One thing though, if we refresh, actually not not for refresh, if we go to the login now or the signup, it still lets us through, even though we're logged in. So let's let's implement something that prevents this behavior. So let's go to here in app j, s, actually, let's move all of this because I don't want to scroll this much here. Let's move all of that object. And let's create. Let's create a folder here called util for utility. And let's create a file in there called theme dot j s. And inside of here, we'll say export default. And we just export this, this theme. So this object, let's save. And here, let's bring it in, let's say import theme, or there is a theme. So let's say theme file from go back one, we're on the same level slash utils. Slash theme, since it's the default export, we can name it anything and here we just pass it to the Create Mui theme, and the behavior should still stay the same. And here, what we want to do is that once this code that's here executes one once the application is started. So what we want to do, we want to get to the token. So let's do const token equals we can do local storage dot get item. For actually we could just local storage is an object, we could just access this property, so local storage.fb ID token. So we get this property. And we do if token. So if we don't have a token, this will be undefined. So this condition would be false. So here, what we do is, if we have a token, what we want to do is we want to get this token decoded. And inside of the decoded token, we have an expiry date. And actually to decode the token, we need to install a library. Let's do npm install dash dash save j wt dash decode library that decodes JSON Web tokens. I know this is a Firebase ID token. But essentially, it's a still a JSON web token. So let's bring that and let's do import j, wt decode like this camel case, from J WT. Well, you can name it anything but just don't. Whatever you name it here, you name it, where you use it just to avoid any errors. So here, let's do const decoded, token equals j, wt decode. And we pass it our token. And now this will have a property called ESP. And if you were to go to the dev tools to the console, you'll see we have this token. Actually, we can't decode it here. But let's do console dot log decoded token. And here, it will find the token it will console log this decoded token and it's got this ESP value whereas it is right here. So this is a time value. That's like a time from epoch. It's gold. So if you new date, and you pass it this. Actually this is in second, so we need to pass it this times 1000, you get exactly when this token is going to expire. Alright, so what we need to do now is we need to compare it with, with now actually, so as the if decoded the code ID token dot x p times 1000 is less than date dot now as a function, that means it's actually expired. So we need to redirect to the homepage or to the login page. So we do window dot location, dot h ref equals slash login. And actually, let's do a, let's do let us do a property a global variable called authenticated, and it has no value initially. So here if it's expired, we say authenticated equals false. Now else if it's not expired, authenticated, equals true. And now here, for our routes for the login and signup, we want to do something where we check that if we're for authenticated, we redirect to the home page. So here, let's actually instead of this route, let's control D on this type of route. Let's create this component. Let's bring it in and then create it. So let's do import auth. Route. And you'll see what this author does in a minute. Components slash, actually, this will be in util. utils, slash auth. Route. And then utils, let's create an Krishna we put it in neutral or let's put it in utility utility. And we're not going to use it, it's not a markup component. So orthros.js. And here, let's do it's going to be a functional components. So RFC tab, I'm going to change the syntax to const. Off route equals props, and then gives us the following. And let's do export default, off route. Actually, let me destructor straightaway what we need from it. So we're going to pass it a component. So from the component, I'm going to get the component with capital C naught, capital C, which is going to hold the component that we passed it. And here we're going to get authenticated, the property authenticated. And we're going to spread the rest of the properties. So if we add anything, it's going to be added here. So here what we return, actually, we can change this syntax to just parentheses so it straight away return something. And here we need the route from react router DOM. And re direct react router DOM. Riley, close that. And here we do route. And we spread the props that the rest props. So rest, and here, we're going to trigger a render method. And so take the props. And it's going to check for authenticated. So if authenticated equals true equals true. Then we run a redirect redirect. And this is so forth indicated, we redirect to slash, which is the home and we close this, else, we just give that component which is going to be either the login route or the signup route. Now props, let's spread the spread the props here, I mean, not arrest. Alright, this should be fine. We need to close the route toggle or route component and let's save. Alright, so one more thing though. Here, we actually pass it authenticated. So click here and hold Alt and click here and do authenticated equals authenticated. Alright, let's save this. Let's go to our app. Let's make sure we have a token and it's not expired. So if we go to login, cool, it redirects us back to the homepage. And if we actually if we delete the token, now, it's not going to redirect us to the homepage. Because this doesn't execute again, only executes once the app runs. But when we implement Redux later, it's going to fix it. So now we Don't have a token, if I refresh the entire page, if I go to login and sign up there, we're gonna work fine. But yeah, once we implement Redux, and we're going to have like a global state and is going to update each time we do something, it's going to this we're going to behave much better. As our application grows bigger, and we will have more components and all these components, or most of these components will need to have access to the data we have on to our user, it would be better that we would implement a solution that manages a global state for our application. There are a lot of situations where something called context API, which comes shipped with react is actually better than Redux. You can look into that if you want. But for this application, it's better to use Redux. And to use Redux, we're going to need to install a couple of packages. And if you don't know what Redux is about, I will post a link to this really cool article that I think you should read to understand what Redux is and why we use it. It will introduce you to concepts like a prop drilling like and funnily enough, it uses an example that's like what we're making right now, which is the social media platform that's similar to Twitter. So if you look here, you will see that it becomes a problem. For example, in here, if we wanted to have the user in this avatar component, we have, we'd have to pass it from the app to this avatar, and then down or down this chain of or rather hierarchy of components. So it becomes really inefficient, and it becomes really ugly code. So what we need to do instead would have something set up like this, where we would have a store, and whatever component no matter how deep or down in the tree it is, it can directly talk to the store, fetch data or send actions that will tell our reducers to mutate our, our global state and change it so that all the other components will be aware of these changes that are happening. Now there's a really cool diagram that I want to show you in this article, which I will link a description, link in the description as well. But funnily enough, I don't want you to read this article. Because I don't know this guy I feel like is trying to use too many like buzzwords and fancy language and try referencing other libraries that maybe you're not even aware, like aware of. But I just wanted to focus on this diagram, because it kind of encapsulates what react is, essentially, we have events triggered from our UI, or user interface, like someone clicking a button submitting a form, whatever any of these actions could trigger an event, and then an event will fire up an action. And this action will dispatch an action with a type and sometimes with a payload as well. And then that type gets received by the reducer. And the reducer will then decide depending on the type of received, what to do, and how to mutate our state. And then once the state has changed, all of our obligation is aware of the state. Now, this might not make sense right now to you. But once we get into the code, trust me, it will make sense. One thing you need to install if you don't have it already, if you're using I'm assuming you're using Chrome if you're not, then do or use Firefox is cool as well. But I don't know if they have Redux dev tools on Firefox, you can install Redux dev tools as a Chrome extension, which will help drastically actually this is one of the reasons why I prefer always prefer Redux over context API, because of this dev tool makes, makes our lives much more convenient. Alright, enough of the chitchat and enough of the theory, let's actually start to implement Redux. Okay, so let's go to our app. I'm going to open up a new terminal, and we're going to install three packages. So NPM, install dash dash safe. First is Redux, which is a standalone JavaScript thing. Second is react Redux. And third is Redux thunk. So react Redux is the library that kind of is the middle middleman between Redux and react. And Redux thunk is a piece of middleware that gives us access to something called dispatch, which allows us to run asynchronous code in in our Redux actions, is something that you shouldn't worry yourself too much about right now, to be honest. Alright, so in the source, I'm going to create a folder called Redux. I like to keep everything related to Redux inside one folder, and here we're going to create two folders reducers and actions. I'm going to create two files, one called store dot j s, and one called types dot j s. Alright, so here in the store. Our store is basically what contains The container of this state. So here we're gonna bring in a couple of things from Redux. So let's do like this from Redux. And here we need create store to create our store, we need combine reducers, which is something when we because we can have all our reduced, you know, reducers in one file, but it doesn't look good. So we we split them into a couple of files, and we will use this to combine them, we'll have apply middleware, which does exactly that. And we will have something called compose. And I'll tell you in a second, why we need that. So we need to bring in funk, which is a piece of middleware or, or store enhancers, well, you can call them that as well. And here, we need to initialize an issue, an initial state, which is going to be just an empty object. And here, we're going to have an array of middleware, just going to have thunk, actually, you can use other middleware, you can create your own depending on what use case you have. And here, we're going to have our reducers, which we actually create, I'm going to create three files, but I'm not going to write anything in them right now. Data reducer dot j s, which is going to handle every all the actions related to our data, going to have root user reducer dot j, s. And we're going to have UI reducer dot j s. And here in the actions, well, might as well create them now. So data actions, dot j, s. And what's the other one user actions? dot j s, and we're not going to have a UI actions because we're going to fire those from both the user and the data actions. So here we do because reducers Actually, we need to import them import first as user reducer, in no particular order, calls input. What am I doing from this is not as five from slash reducers slash user reducer, I'm just gonna copy this, paste it two more times. And here, I'm going to say Ctrl, D, and do data reducer. And here, I'm going to do UI, reducer, whoops, reducer. And here, we're going to combine them. So reducers equals, combine reducers. And if this code is a bit confusing to you don't don't make it confusing, because this is just one thing you're going to write once, and then you're going to do the actual code inside the actions themselves. Alright, here, this is our actual state. And here, we get to name our objects inside the state. And for the user data, I'm just going to name it user and give it the user reducer. So everything that comes from the user reducer will be stored inside of this user object. It's not Yeah, inside the user object inside our state, we're going to have data. And this is going to be from data reducer. And we're going to have UI from UI reducer. Now we can create our store. So we do const. Store equals create store. And here, we pass it through things are reducers. And the second is our initial state. And the third will be usually it would be just the middleware. But if we were to go to our application, and we do have 12. And we go to the Redux extension. I don't know why it's saying that we have a store, we don't actually have a store. But to have like, let's look at the Redux Dev Tools set up because there's this, this long string that that we need to put here, this one right here. So window dot Redux dev tool extension, we need to apply it as a store reducer. So that we can, so that we can see the data shown on that on that. Extension, so apply middleware. And here we spread our array of middleware, so dot dot, dot middleware, and then the second argument to compose we actually paste that the string we copied from From the React Dev Tools GitHub page, so we save and it formats. Let me close these console windows. Yes. Okay, so this is our store, we actually need to export it. So let's do export default store. So this is basically what contains our application state. Now we need to actually give it to our application. So we can do this by going to App dot j, s. And here we're going to bring two things. Let's say Redux. Here, we need to bring something called provider from react, Redux. And what do we need, we need our store. So store from one level, or on the same level rather, Redux slash store? Yeah, we just need these two things. And we need to wrap all of our application inside of this provider. And it doesn't matter, it can wrap the movie provider or the movie provider can wrap it, it doesn't matter. They don't interact with each other. So we can just put this provider and it takes a store, which is going to be our store, we close this. Now let's cut everything and put it inside of this provider. So now, as you can see, everything that's inside of this provider will have access to our store, which is our state. And by the way, we can remove this div up, because it's not stealing anything. It's not doing anything, actually, that's safe. Okay, right now, we just introduced Redux, but we don't have anything. And if we would go to our application, and refresh, my dev server still running. If we go to Redux here in our state, actually, we haven't initialized that. Okay, so now what we need to do is that we need to go to our data actions. Rather user actions, let me close everything, user actions, because what we're going to start to do is we're going to start to move this code or this login code from the login component and the same from the signup component, and move them into the user actions. So here in user actions, I'm going to actually Before that, we need to create some types. Now, you don't have to create types, these types can be just strings, but the fact that we create them and put them into variables, it makes it impossible for us to make a mistake, because we can actually pass because if we make a mistake, name and a variable, it's not going to run so that it makes it easier to spot our mistakes. So let's do export const. And here, I'm gonna create a couple of types. First one will be set, authenticated. Thumb to cated, which equals actually exactly that, but as a string. You also need oops, a type for set. And it's, it's just a convention that we named them in all caps, set unauthenticated, which is going to be the same as a string. So paste it here. And we need also a set user type called set user. What else we need a tie. Now we're not going to use all of them in this video, but I just know that we're going to need them later. We need a loading user. She's gonna be just that. We actually let's, let's put a comment here, say user use reducer types. And here we say UI reducer types. And we're also going to have data reduce types. And here for the UI reducer, we're gonna need export const set errors. I'm gonna just copy this. We're gonna need what else loading Ui Ui like this UI clear errors. I think this is it for now, if we need any more types, we're gonna create them. So let's go to user actions. And let's bring in as bringing these types that we need for user. So set user, we need set errors. We need clear errors, and we need loading UI. Ui from go back one level and go to types. And here, we're gonna actually just move this code that's inside of the handle Submit. So the login code, so let's copy, actually, from here, this axios call, and let's paste it into, let's call this action, export const login user. And it will take user user data. And here, it's gonna, we're gonna as well get this batch. Because here we need to access, we need to use the special because we have some asynchronous code. And so we paste that code in. But actually, here, we need to set the loading to true. Actually, we can remove the loading code from login, and we can even remove it from the state. So we can set the login from the action itself. So here, what we need to do is we need to say this batch. And this is where we actually send an action. So this action is going to have a type. And this type will be loading UI, you can start to see how this works. We dispatch a type. And then we will catch the type from the reducer. So let's actually just check if this code is sound. So we log in, and then when we get the data back, okay, so here, when we get the data back, we want to, we want to actually fetch the user, I'm going to create a new account, I'm going to create a new action that we for some functionality that we didn't even have in the last video, and it's going to call this get user data. And it's not going to have any, it's not going to take any argument because it's going to use the token that we got back. And it's going to use this batch. Actually, before I do that, now we get the token. So if we get here, that means we have the token in res dot data dot token. So what we need to do, we not only need to set it in the local storage, but now each request that we need to send to a protected route, we need to add the authorization header. But it wouldn't be efficient for us to each time we send the request, we add we add it there, we can take advantage of this axios axios, default headers thing. And we can do axios dot default, dot headers, dot common. And by the way, this is in axios GitHub documentation page. And here, the header will be authorization. and the value of it will be the actual token that we got plus bearer so we can do bearer. I should put this in a variable. So we can say const, FB ID token equals template, string bearer and space and then we do res dot data dot token. So now we can give this variable here. And we can as well assign it here to the headers. So now when we do this, each time we send a request through axios, it's gonna have a header, an authorization header with this value even to not unprotected routes, which is not a problem at all. So here in get user data, we can just say axios dot get. And if you remember, we can send a get request to slash user, which will get us the user data. So here we do dot then recce. So if we get a result success result, we need to dispatch an action. So here we dispatch an action of type. And this type will be set user. And this action actually takes a payload. And a payload is basically some data that we send to our reducer, and then the reducer does something with it. And the data here would be just response to data which we get back which is the user data. And of course, we need to handle in case there's an error. Catch. And if we get an error here, we just console logger console dot log error. All right. So We get the user data when we log in. And here what we need to do when we get the data. So there is no state because we're not in the component. And we don't log it. So here, what we need to do is we need to dispatch, the get user action, we can actually just do this after all of this, we can just actually just do this batch. And we can dispatch this function that's right here. So we say, Get user data. And it's going to call this and thing is Oh, actually, we need to redirect. So what we need to do, actually, we need to pass. So here, when actually, we need to pass the history from this component to the action, and then the action will use it. So we can put it as a second parameter here, let's call it history. And here, we just do history dot push, and it will actually work it will read the redirect even from from the action. And so here, like we get user errors, and we need to dispatch another another type. Actually, we were not handling these types, yet, you will see in a moment what these types do. So here we need to dispatch another type. Another action with the type, clear error, clear errors, just in case there is any errors in our form. And then we actually redirect. And if there is any problem, we need to not set date, we need to dispatch an action with the type set errors. And with a payload of error, dot response dot data very similar to what we have inside the component. But this will actually do this to the global state. Now let's let's go to the reducers and handle these types. So let's go to the the user reducer. So here, we're going to need the actions, I mean, the types that we have as well. So let's do a springing set, we can actually just copy not from login from the actions, we can just copy these types from that we've run, Oh, actually, I forgot something, we need to bring in axios, because we're using it inside the actions. So from axios. And here, we copy this, we go to use the reducer we paste them. And here is where we need to give an initial state an initial state to our This is not the global state. But this is remember this is what's stored inside of this user. So this real reuse the reducer is actually this state, of course, it's going to change it's not going to stay the initial state. So we're going to have a an authenticated Boolean, which is going to be false by default, we're going to have credentials. If you remember, if you've seen our API, you know what these are, we're gonna have a likes array. And we're gonna have a notifications array. And initially, everything will be empty. And here we will export default function, and this function will take a state. And here we give initial state as the initial like the default value of the state. And the second parameter is going to be the action that we receive. So here, we're going to have a switch. So depending on the action, we're gonna do something actually not depending on the action type, we're gonna do something. So here, this is where we catch all types. So cat case, first one will be set authenticated. And here, we do remember this word switch. So we do have a colon here, and we we here, if we get the type set authenticated, this is a simple type that I'm going to actually call from the app dot j s, this just returns the state. And each time we return the state, we actually spread the state that we already have, and then we change a couple of things in it. Here, what we changed is the authenticated, we make it true. And let's handle the set unauthenticated state. We're not using actually these two types in this video, but we will set them for future use. And here, we just, if we set on authenticated, this is going to be used when we try to log when we log out. So here we just actually returned the initial state which has authenticated a false on a no data. Now here we can handle the set user type, which we just dispatched from the user actions. And here we simply return authenticated, we set it to true because we got the user data. And we need to spread action dot payload. Because remember from our API, when we send our token to slash users, and we get the data, we actually get something like this with credentials and lights and notifications. So if we just spread it like this, it's gonna bind the credentials to credentials, likes the likes and notifications to notifications. And of course, this is a switch. So we need the default case. So default, we just return return to state that we have right now, which is this. Alright, so let's save this. And let's go to our login. And here in the login, now we need to connect to this component to to the Upstate. So here we bring in two things, let's say here, Redux, Redux stuff. And here we bring in something called Connect, which does that. And this is from react Redux. And we need to bring in the action, the login user action. So here we do import login user from. So we go back actually one level to Redux slash actions slash user actions. So here, instead of doing what we did earlier, we actually just do this. Actually, we need to bind it first. But let's just type this, this dot props, oops, this dot props dot login user. And remember, we pass it the user data, which is user data right here. And we pass it this dot, props dot history. so that it can use it to redirect us on success. And here are the bottom, we need to actually use Connect, which is another higher order. component. Let's cut this and let's do connect. And let's leave this empty for now. And the second one will be our width style styles login. And here it it takes. It takes three things, but we have those three things we need to one is called map state to props. We'll create these in a second. And one is called map actions, to props. And the map state to props whose will be const. Map state to props, it's going to be a function that takes our global state, and returns. So now it takes global state and then from the global state, we take what we need, basically. So right now what we have is we have user data and UI. And for the login component, we don't need data because we don't need to show any screens in the login thing. So it makes sense that we only get the user and the UI. So let's actually do that. So let's get user. And we'll be State DOT user. And UI will be state.ui. Alright, UI like this. And here, we need to say as well const, map actions, to props. And this will, we're telling which actions we're actually going to use. And in this case, we just need logged in user. So we passed them here. And actually, this will be props. All of these will be props. So let's add them to our prop types. So here we say, login user is a prop types. It's actually a function. So prop types.func.is, required. And we have user which is an object, I'm just going to copy this. And then we have UI, which is one object, and I'm going to paste this. So yeah. Alright, so now the user and the UI are actually brought in from the global state and mapped into our component props. So these will be in our props right now. And so is going to be the login user. This is why we can actually here do this dot props dot login user. And here, what we need to do is the loading now we no longer have it in our local state. We have it in the props, so we can get it from the props. But of course, we can't just get it like that. It's inside the UI. So we do UI and then colon, and we get it from inside the UI. And I think this is it for here. One thing we're not doing is we're not actually here when we get the errors, we're not handling that. So user actions. Here. When we do set errors, we need to handle that from the UI reducer. So in UI reducer, we need to Bring in set arrows and clear errors and loading UI actually as well. Loading underscore UI from go back one level and then types. And here we need as well as an initial state for this. And our UI reducer will hold the loading, which is initially false, and an errors object, which is not initially. And here we do the same thing, export default function, which will take a state, the initial state, and we'll take an action as well. And here we do a switch. And here depends on action type, types type. Here, we have a list of default list or default, which is returned state. And here we can do case, what's the first ones that errors? So if we get any errors, we actually, we just spread, so we just like spread the state. And which, what do we do actually? Actually, yeah, we said the loading to false because we finished loading, we actually got some errors, and we set errors to our action dot payload. And if we get the clear errors, case, we do return state. And we said the loading false, and we set errors back to No. We have loading you actually as well. So let's do case. Loading. UI. Oops. Here, we just return Oh my god. Return state. And we just set the loading to true. Alright, is that everything, get set errors? Clear errors, loading UI. Okay, this look looks good for now. I think this is everything. Let's check if we have any errors. We don't actually stop this and run it again. Hmm, no errors. That's strange. Okay, so let's open up the console. I mean, put them side by side. Do we have a token? No, we don't. Okay. All right. Oops. All right. That's what our first error login user is not a function. Is it not? Because I didn't save this file. Okay. Okay, let's try to login. So user at email, com 123456. Login. Oh, actually login successfully. And we got the token in the storage. Let me delete the token. Actually, let's look at the Redux state. So state. All right, cool. We got our, like user details mapped into our into our user object and the state. Oops, let's go back to row Yeah. All right. So we got our user we got authenticated equals true. Let me actually reload to see the initial state. The initial state is what we had it and authenticate to this false. And if let me actually try wrong credentials are interesting. We get an error here, but we don't get it here. Hmm, I get errors here. But what they don't show up. Okay, okay. It's because these props don't come straight away. Actually, we need to do component component will receive props and this takes Next props. And here what we need to do simply is this dot set state. Yeah, we need to get the errors and then set them to our local errors. So set state and we do errors equal next props.ui that errors. All right, actually, we need, we need to actually put a check, because we will always be receiving props. And this will be inefficient, we need to do if next props.ui got errors. So if we get this, then we actually set the errors to the errors object. This should fix it. Alright, let's look at our state, we have no errors and, and there we go, we got our errors. And they're shown on our login form. And if I fix just this, say, user email.com, or hit send, I need the password. If I have a wrong password, code, get the general one. And then if I have the right password, we get redirected. Sweet. Let's go to the signup component. Where is right here. Okay, we need to actually first let's create the action. So let's go to user actions. And here let's create an action that's like login user, but it's the sign up, it's actually going to be very similar. So we can just copy this, and then paste it here. Instead of login user, this will be sign up user, it's going to take the same stuff here, let's call this new, or this way, let's Ctrl D, and then call this new user data. Just for readability. With dispatch, login, loading user loading UI, that's fine. We'll change this to slash signup, we send the request to slash signup. And the same thing happens here we said the token will get the user data and we clear the errors, we push the home page. And we set the errors if any cool. But one thing though this code is repeating itself. So let's let's make it into a helper function. So let's cut this. Let's make a function here. Let's call it set authorization header. It will take the token. And here we will have that same code. But instead of restaurant data token, it will be just token which is this function argument. So we can just actually call it from here. So here as well. So here we just do SATA theorisation header when we pass it res dot data dot token. And let's copy this and instead of all this in the login, we paste it. So set authorization header, read set token, header, data dot token. Cool. Let's create actually another action for for logging out. So const, export const log out user. And this won't take anything and think you won't even take this bachelor will think that Well, alright. Yeah, well. Alright, so here, what we need to do is we just need to remove the token from the storage. So we do local storage, the rim remove item, and we just pass it the name of the item which is as a string, of course, FB ID token. And, and here what we need to do, we need to remove the header, the authorization header from the defaults of axios. So we can actually just delete the entry by doing delete like this axios dot headers, not actually dot default, defaults, dot headers, common and the header is authorization. And here we need to dispatch a type an action rather and of type set on authenticated our product, we brought the end and we have it in types. So this will clear out our user state if you remember, if we go to use a reducer it will set unauthenticated will return the initial state and it will it will set us back to being not authenticated and having no credentials and nothing. Let's remove these unused imports right now so I can get rid of the warning. Let's save this. And this is well let's go to sign up and actually Start using that. So here we're gonna bring in. So we're gonna bring in oops import, connect, let's say Redux here Redux Redux stuff. And here is to connect from not equal from react Redux. And we need to bring in the sign the sign up user from Redux, go back one level, go to Redux slash actions slash user actions. Alright, right. And let's go to the bottom and actually connect the components. So here we do export default Connect. And we pass a map state, to props. And a map state. Now, map actions, to props. Close this, and then we open another parenthesis, and we close another set of parentheses. And here, let's say const. Map state, to props. equals equals, it takes the state and it returns. So we need the user. So user equals or colon State DOT user. And we need the UI. So state state.ui. Okay, so yeah, we need the map. Actually, we, we can just pass it like this, because we only have one action. So it's still clean to type something like this. So log out user, without actually putting it into a variable and putting it there. Let's add them to the prop types. So we have user is a prop type stock, almost typed user object that is required. And we have UI, shares, prop types, the object that is required. And what else we have the function log out user is a prop types.funk.is required. All right, and we brought the function. So we need to use it here when we submit. So we can cut all of this. Actually, we already have it in the other code. So we can just here we just say this dot props. Remember, it's in the props already logged out user and we pass the new user data or just call it user data here, let's change this to a new user. They that doesn't make that big of a difference, but it's more readable. So this dot props dot history, we pass it so that we can redirect. And yeah, I think actually, now we need to set the errors. Let's just copy this from login component will receive props. But here, and let's remove the loading from the state, we keep the errors because we can set them from here. And here we from the props we get from the props from the UI, we get loading, removed the loading from the state, and this should be fine. Let's save. Let's see if we get any errors. We do. logout user is not defined in signup. Oh, not log out, sign up. Why did I put log on? So actually sign up. Okay. And here's what sign up. Not sign up this dot props dot sign up. Alright, so that should be fine. Forgot to sign up. Actually, we're logged in. So let's go to application. Let's remove the token. Let's go to sign up. Actually, we need to fix this because it needs to know. Okay, we got to sign up. We'll fix the author out in a bit. Right. If we send a call, we get the errors. And let's try to sign up a new account new six@gmail.com 123456123456 handle the new six cent sign up. Cool. We got redirected. We got our token. Everything works. All right. What else? Let's go to the app. So here the way I want to check is that I want check if the token is in the storage, but this authenticated. Obviously it's really bad practice to have global variables like this. So we need to call the action from, from, from our user actions and set ourselves to to be authenticated and then edit the state accordingly. So here at the top, here under Redux we're gonna bring in, we're gonna bring in two types, because we can actually call them from here as well. So we're going to bring in set authenticated, we're going to bring in set errors, or do we I don't think we need to actually know. So just set authenticated from go back one that actually we don't get on the same level Redux slash types. And we bring in the logout user, because in case the token is expired, we just log out from here logout user and get user data, how we created get user data we have yeah. Oh, yeah, of course, we have from Redux slash actions slash user actions. And here when we compare the token. So if it's expired, we just do, we can actually do store dispatch. And here what we need to dispatch, we need to dispatch the action log out user. And that will delete the token and log us out. Let's get rid of this authenticated variable. And we are as well like set the href to slash login, so we get redirected. And let's remove this authenticated equals true. But instead, let's do store dot dispatch. And here, we dispatch an action with a type set authenticated, which just sets authenticated to true. And then when we go to the homepage, we actually get the data or when we call get user data, we get the data. So let's do store dot dispatch. So after we dispatch that we are authenticated with dispatch, get user data. And actually, actually for this to work, because when we set axios default headers, when we actually refresh the page, those headers, like those defaults are gone, and axios is re initiated again, we need to again do axios dot default, or we need to bring in axios. And VS code did me the courtesy of doing it itself, but it did this capital thing. axios, the default dot headers, dot common. And here we say authorization. And it's equal to the token that we have up here. Not rochen token. All right, and then we get the user data, this should work. But because we got rid of the authenticated thing, we can't use it here. So let's delete that. And but I think our throat will complain because we're let's fix authorizers Well, we might as well, since we're here. So let's bring in Connect, we need to connect to this component as well to our, to our state. So it's bringing connect from react Redux. And now actually, that's just connect. And let's explore the fault Connect. Map state, to props. And we don't need any actions. So we can admit that the argument and here we do const map state to props equals, it takes in the state. And here Oh, actually, this function returns an object. and here we can actually even get a certain key within an object. So we can say authenticated, and then do State DOT user dot authenticated. And you will get just that one key. One property. And here, it's it's going to be in the props. So nothing changes here. So we get authenticated from the props. And then we get here, and we redirect if needed. Let's do actually prop types as well, because, you know, you never know what's going to happen, because they're prop types. And it's always good to practice these, these best practices so that you get used to them. Alright, so prop types. And here we say, what is the author route of Route dot prop types, equals, and what do we have? We have just user so prop types dot object Thought is required. Actually, this is a capital P. and everything should be fine. Let's save all files. Sign up. axios is defined Oh, actually, we don't need axios anymore here. Because we're doing that from the user actions. We have axios in the login as well, let's get rid of that. All right, we will use these. So let's just ignore that warning for now. Let's go here. Let's see we have a token. And if we click here, it redirects us. And if we delete the token, now click here. Hmm. Somehow that arthralgias, not working. we deleted the token. But we're still we're still logged in. Oh, because we need to actually, oh, this executes once the app is submitted, actually, it's behaving as behaving Normally, I don't know what I was thinking. Because that would be triggered. Actually, because a login would not be triggered by someone deleting the token, it will be triggered by us deleting the token from the app, there will be a login button and that login button, when you click it, it doesn't just delete the token, it actually sets the state to unauthenticated. So yeah, no one will actually go and delete the token like this. If they do, they will actually break our app, and we have no way of fixing that. Alright, so this is our application right now. And right now we don't have a profile. So let's actually create that let's create a section where we show the profile because we if we go to dev tools to Redux, we actually are fetching the profile, we have all these details, we just need to show them on the interface. Alright, so let's go to the homepage is the homepage here. So here we have this text profile, and it's actually put a component profile, which we haven't created yet. Let's import it. Import something that hasn't been created yet. Because why not? Alright, let's go to components. Let's create a profile dot j. s. And here it is. Do RC top whoops. Again, it didn't work. Come on. Yes, Third time's the charm, I guess. All right, so let's remove the export. And here we're gonna need a couple of things. Of course, we're gonna have prop types. So prop types. What is that prop types from prop types. We're gonna need with styles. For material you wore slash core slash style slash, with styles. We're gonna need some movie stuff. So we're gonna need the button. From material UI slash core slash button. When I know we're going to need some icons actually need to install the package for icons. So let's open up a new window and do an NPM, install dash dash save to material, UI slash, slash icons. let's actually look at the documentation. So basically, these are all the so we go to styles, icons, these are all the material, Google Material Design icons, there are SVG icons. And the way you use them is just like you import the icon with the name of it. So let's say delete. So import, add material, UI slash icon, slash delete, and you use it as a react component. And if you would go here to see the full list of the of the Google Material Design icons, you know, I said the whole thing again, you can see all the icons and if you want to use one, basically, you just camel case the name so for example, Play for Work will be not camel case basketball case. So it would be like Play for Work, and you will get that icon. Alright, so let's head back to our application. We're not going to use any icons right now. But here at the start, actually, we need to first let's say with styles, styles, unwrapped the profile as well. And then let's wrap the entire thing. And here that's connected, connect, which we haven't brought in yet and brings the connect from HTTP to okay VS code. Perhaps the To props. I don't think we need any actions for now. So here let's do, we bring Connect, not actually from react Redux. And we need to create the map state the props. Takes the state the usual, and it returns an object. And we only need to access the user so users data user. And all we need to do the prop types. So let's do what is this profile. So profile, prop type types. We have user some object, it's required. And we have classes from a spouse. Almost typed classes. And this is a required call. Okay, so here at the start of the render, let's get get classes. And let's get some details from our user. So from user let's as well destructor, from this, actually, inside of us that we have credentials. And from that, we're going to need some stuff. This is some nested destructuring. So we're going to need handle, we're going to need to create the art image URL. What else? Oh, yeah, we need the details. So bio, and website and location. Alright. So this is what this is after credentials. I confused myself a bit. Yeah, that's it, we need the credentials. And we need the Well actually, actually, we need to create another property I forgot about. So inside the user we're going to have. So here we put a comma, we do loading, we're gonna have a loading for the user. Let's not forget to say this equals this dot props and save. So formats, we're going to have actually a loading property. So when the profile is loading, we can see a loading skeleton. So which is different to the UI loading. So let's go to our user reducer. And here we need to bring from types loading user. And here we need to initialize a property loading with false. And here, let's add a case for that case, loading user. And all it does here, we just return the state. And we do loading equals true. And here, when we set the profile, we actually stop the loading. So we do loading equals false. In case it was true. So let's save this and let's go to use the actions. Let's bring it in as well here. So from types loading user, oh, it's already created, actually, it's already in the types. Okay, so loading user. And here, when we try to get the data, that's before we try to get the data, we dispatch an action with the type loading user. I think we're done with this part. Yeah, we're done with this part. So let's go back to our save the home, let's close this. Let's close this, let's not worry about this. Let's create concepts styles equals empty object for now. I noticed I'm spending too much time writing CSS rules, which is not the main focus of this course, on the series. So what I'm going to do for now, I'm just going to paste in like stars for this profile, because there's quite a bunch of them, I don't want to I don't want to waste time doing that. I'm gonna Of course, post the link to this, this object style subject. And so you can copy it and paste it right now as we're doing this video. And then you have everything styled. And you can go Of course through it and and you know, and understand what's happening the way I wrote what I did. Okay, so here, we're going to actually create one object and then return it. And then we're going to call it profile markup, because this markup is going to be completely different depending on whether we're loading or whether we're syndicated. So here we have, let's do let profile mark up. Now we're going to have this is going to be a bit confusing. We're gonna have two ternary operators. So the first one, let's say, if not loading. So let's do question mark, parentheses colon parenthesis. So if we're not loading, show this for loading show this. So for loading let's For now, let's Just show a paragraph say loading dot dot dot. And if we're not loading, don't worry about this, it's going to be fixed once I write anything here. So if we're not loading, which check if we're authenticated. So if we're authenticated, show this, else show this. So if we're not loading, if we're loading, show loading, if we're not loading check for authenticated, if we are authenticated, show the profile of authenticated. If not, we're going to show you know a section that says there's no profile data, please log in or sign up. And we will show two buttons for users to do exactly that. So here I'm going to use something called paper from material UI is basically just like, Where is it? So component demos paper. So yeah, this just this kind of surrounding frame, thing that stands out from the background, it looks like a card because basically a card is built on top of a paper. So here with the paper, I'm going to give it a class name of classes, paper. So we already have the style. So this styles will apply and it will look cool off the go. So here, I'm going to do a oops. So this time here, let's do a div with a class name of and then this profile. And here, I'm going to have a wrapper for the profile image. And actually, we could still use traditional class name, you know, strings, we can, if you go here, and you see, we can still use stuff like this. So inside of profile, we can say and space, and then we give the class and it will still work like traditional SAS. And yeah, so we can do that. So this is profile image, actually not image profile. So profile. Or is it a profile dash image. So here inside of this div, we're gonna have the, the image, Sony image, or just image tab, and the source is going to be image URL, we already disrupted that, and the alternative will be just profile. And it's gonna be okay, I'm just going to leave it like that. For now, here, we're going to do a horizontal ruler, which I've already styled to not have any border, so it will be invisible, just create some space between them. And here, here, actually, I'm going to put a link, but this is not going to be like the normal react link. Actually, it is but indirectly. But here, let's first bird div with the class profile details. And I'm going to bring in something from material UI. So this is not more stuff. This is Redux stuff, Redux. And hear from Mui. I'm gonna bring in what is it from material? Why is it not until the sensing material dash UI slash core slash link. And I can name it anything, because the default is the default. Export, I don't want to confuse it with the React router Dom link, which we need to bring in as well. So import link from react router DOM. And here, where are we? So we're here, here, I'm going to say, movie link. And I'm going to give it the component of link. And here, it's gonna have the two, actually, it's going to be like this template string, it's going to be two users slash, put a variable there. And it's going to be the handle of this user. So this is going to be like a title that says the name of the user, and it's going to be a link as well to that to the page of the user, and the color will be primary. And since this is built on top of typography, we can give a variant to change the size. And I'm going to give the vine variant of H five, header five, and this will say at handle, just like in Twitter, and here, we will do an HR. And here I want to show an always show the details of the profile. So first, first will be the bio. So and these, we don't have to have them because a user can have no bio, so it's going to be no. So what we need to do, we need to first check if they have a bio. Then we show the bio. So here what we're going to use, we're going to use typography, typography. And is it important from the right place? Or not like this, I need to shake this. So typography need to put up with movie stuff. Okay. So here, this is going to be typography of variant. What variant do I give this body to, I guess, think its body to pretty sure its body to so here bio, biome bio. And after this, I'm going to put another HR to make some more space. And here, I'm going to check if a user has the location. And here I'm going to do parentheses because there's going to be multiple things I want to use like an icon on the left, that shows a look location icon. And this is called location on me bring it in from icons. So this will be here. Import location on from material UI should not slash core slash icons slash location on I'm going to need two more icons, so might as much excuse me bring them now. I'm going to need the link icon. I'm going to call it link icon. I own icon. And it's gonna be from icon slash link. Shoot me check. I don't remember what the other icon was that I need to bring. styles. icons. calendar, but calendar Yeah, calendar today. Okay. All right. So it's gonna be let me select this control the calendar today. Alright, so here. Where are we? So location on? Color primary? Yeah, that's it. And here next to it. I'm going to do space, actually without which is do spawn location inside like this. And I'm going to put an HR but it has to go inside of here. Because if there is no, if there's no location, I don't want to put two hrs on top of each other. Or this has given me a must have one parent element. Oh, yeah. Okay, let's wrap this in a fragment, which if you don't know what it is, it's a react component that actually doesn't render anything, but just wraps things so that they will be in one element. So let's actually bring that in. fragment. And here we need to show the other way. Yeah, the website website. And, and, and two parentheses expression. So another fragment as well. And here lets us use the link icon, so link icon with a color of primary. And, under the link, I'm going to actually have a normal anchor tag anchor tag with an H ref to the website, I'm going to give it a target on the scope blank so that it doesn't open in this window opens in a different window. And this is a react thing you have to give this REL equals no opener. No referrer otherwise, React will complain. So we close this on inside of her. I do like oops. Because this icon is kind of thin on a give like some it's kind of white, I'm gonna give some space and then put the website like this and put in like a horizontal ruler, HR. And here under the website, I'm going to put the the joint since date thing so I'll put the calendar to the icon with a color of primary again. And after I'm going to put some space like this, and I'm gonna put a span and so joint and here actually we need to format this so we need to bring in DJ s so let's say important they j s from DJ s. And where are we we're here. Wait here. So here I need to say de JS past this the created art And here I want to format and pass a string, say M, which is going to say like the month but in three digits, line three letters, and quadruple why to just show like the the year in a normal format. Alright, so this is for the profile. But here I want to show as well if we're not authenticated. So here let's do paper, again with a class name. Oops, class name of classes, dot paper. And close this. And then inside of here, we're gonna have some texts type Pog Rafi with a no color variant of body two. And I'm going to give this a line takes a property align, and say center. So the text is actually aligned in the center. And let's say no profile found, please login again. Here, I'm going to put a div div, and this is going to have a class name of classes dot buttons. button, what buttons? buttons, yeah, buttons. Alright, so buttons. And here, I'm going to put a button. Did we bring in button? We did okay, I am going to put what is this first button. And this will have a variant of contained, contained like this with a color primary color primary with a component of link so that we can actually go somewhere within our application with a tooth to slash login. And this button will say login. And we can actually just copy this. Copy this button. Right here. We'll have the color of secondary and it will go to sign up. And he will say sign up I think this is it for our profile markup. Yes. So yeah, for logged in, we will show this for not where shoulders for loading will show this. Okay, let's save. Our paper is not defined how we need to bring in paper. So let's copy this. Select this Ctrl D save paper. What else? authenticated is not defined? How come? Oh, we need to take authenticated as well from user so authenticated. So theme is not defined. Oh, we need theme we need to spread theme here. Actually, we need to take theme. So do like this theme. And then wrap this in parentheses so that it's returned from the function. Let's save and it should fix everything and it does. Cool. Oh, okay. So our image is massive. But the rest is cool. Because this image needs the class what is the class actually profile image this so what is the image? Class Name? Equals that at save Oh, that's a line to the left for some reason. That's what from actually Oh, actually the div that contains his his image dropper and not not not profile image. So delete this and then so rapper. Alright, cool. So our profile is like this, we show the website person has Twitter as their website joined in March to 2019. And if you would like logout, of course now manually will implement a logout button in the next episode. When we finish up the profile call, we get the buttons and click on login, it goes to login and click on Sign up it goes there. If I would sign up as let's say john, who doesn't have any bio or anything. Go ahead and turn. There we go. We don't get the details that this user doesn't have and the image is running quite nicely. Let's start implementing some action buttons where we can add details for our user. Alright, first thing I want to work on is the image upload function. Want to add a button when we click it, we can select an image and upload it to our server. So let's go to profile Jess. And here right under the profile image, we're going to add an input input of type file. And it's gonna have an ID of image, or let's call this profile image or image upload or image file. image or image input, I don't know, I didn't feel creative in that moment. So onchange, eight equals. So this input itself is going to trigger the, the handler function. So let's call this handle image change. And this the way a file input file input works is that the on change is triggered each time you select a file. So if you click and you select the file, the on change is triggered. And the way I want to set this up, I don't want to set up two buttons where you select one image, and then you click Upload. Because that's a bit too much for our profile, what I want to do is that once a user selects an image and clicks, select, it automatically uploads to our server. So let's go here and create this handler method. Let's call this handle image change, it's going to take an event because it's an input, after all. And here, what we want to do is we want to get the file. So how we get it is let's do const image equals, because this is a file input event target, it's going to have a property files. And because we said file, we can only select one, but it will still have them in an array. So let's select the first one. so files zero. And here, we can open like do a comment here, like send the server, I just want to look at it right now and see if it's working. Okay, so we can actually spend some time and style this and change these, these things that come to choose File message and remove this message. But what we can do, which is more easy and convenient is that we can just hide this and put a button here, and that button will trigger the input. So what I want to do is I want to add this a property hidden with value hidden, so we don't see this. But what we do is that we add a button next to it, that when clicked it triggers this input. So it's the icon, icon button I'm going to use which is a it's built on top of button is just an icon that triggers an event and then you put a button inside of it so that it looks like well it has a button. So on click equals. And let's call this handler, handle, edit, picture. And let's give it a class name of button. Remember, we've already written those CSS rules. So here I'm gonna put a an edit icon, which if you go to material UI icons or Material Design icons, you'll see it's just a pen. And I'm gonna give it the color primary. So let's bring these two things in. So here, under Mui stuff, I'm gonna do import icon. button from material UI slash core slash icon button. And the edit icon, import, edit icon from material UI, slash icons slash edit like this. Alright, so let's create this handle edit picture function. Go here and say, handle a picture equals takes no arguments. And what it does is that it needs to find this input and just click it basically. So what we need to do is const file input. And we can get it since it has an ID. So let's do document dot get element. I don't know why I'm not getting IntelliSense here, slow, okay, so get element by ID, and the ID will be OCR the image input. Now that we have it, we could just say file input dot click, simply and it will actually click it which will open the selection file selection window. And then when we select an image, it will trigger this. So let's save. And there we go. We got our button and the other input actual input is hidden, and the button is already placed in its perfect spot because of the CSS rules that we pasted in the last video. So if I click it, it will actually trigger the input. And I can select a file, and I don't see the name of the file selected or anything, it's just done behind the scenes. Alright, but what I want to do actually, this button, and maybe it's not that descriptive, so I want to use something called a tooltip. Which if you go to material UI on component demos, right here, tooltips is basically when you hover over something, and you see this message that kind of helps you tells you what this does. And you can place it on any side, I prefer the top. So the way you do this, you just bring in this tooltip from material UI, core tooltip. Let's copy that. Let's go here under Mui stuff. let's paste that. And the way it works is that you surround your element with a tooltip, like this. So if you want this button to have a tooltip, you just surround it and you put a title and a placement. So here, our icon button here, let's cut this, and let's do two tip, it has a title on here, the title, I wanted to say, edit profile picture. And the placement is dope. I think the default placement is bottom. So okay, let's paste that. If you want it on the bottom, you can, you can do that. But I just prefer the top. So let's save. And let's see what it looks like. Alright, cool. So we get our message when we hover over, which is very helpful. So it's good UX acts, practice. Alright, so let's actually send our file to the server. So not here, here, what we need to do, we need to send a request of top with with form data. So let's create that. So let's do const const form data equals new form data. Pascal case, because this is a class. So let's do form data dot append. So we're going to append a value like an input to the to the form data. And this takes three things, a name, which is going to be a string, and let's just say image. This doesn't matter because we know what our server code looks like. But let's call it image, or value, which will be image, which is this file, and a blob, which is going to be image dot name. And here, we can actually send an axios request from here. But of course, since we have Redux, let's centralize everything in the user actions. Plus, we need to trigger the user loading action. So let's do this dot props, as call an action that we haven't created yet. It's upload image. And let's pass it this form data. Simple as that. And let's go and create this action actually. So let's go to actions, user actions. Here at the bottom, I'm going to do export const, upload image, it's going to take form data, and then do the following. So let's do axios dot post. But actually, before that, let's call the, the user loading action. So let's do let's dispatch an action with type, not user loading loading user. And actually, I forgot to include the dispatch. So here, we need dispatch. So let's add it here. So dispatch. So after we dispatch the action, we can send our request. So post, if you remember, this is to slash users slash image. And the data will be that form, not don't form data. And here, then we get a response. What we need to do here, we just dispatch the get user details, get all get user data, and then get like basically get our user. So then here, let's do catch error, which is console log error. And here, we don't need this result. So we can just have an empty function arguments there. Yeah, I think this is for the upload image. That's actually important in the profile. Here, import. Let's import the logout function as well because we're gonna, we're gonna use the logger actions Oh, we're gonna use it later. So log out user. And upload image from go back one level Redux slash actions slash user actions. Alright, let's go to the bottom and a create a map actions to props. So here's the const. Map actions, to props equals an object which has logged out user, an upload image Unless passed, that is the second argument to our Connect. So map actions to props. And let's add them to the prop types. So here, let's say logout. user is a prop types.func.is. required. We need to upload image, oops, upload image, prop types.funk.is required. Alright, let's save all files, and the dev server is still running for me. Let's go to the application. Let's click on the on the button, let's select this guy's image, and it loads and there we go, we got our image, and even uploads on the spot right there, because we dispatched the get user data action. And if we do it again, we put this monkey image. And there we go, we get the image uploaded again, so cool, it's working. And if we go to our data or storage bucket, we see that, of course, the images here. So the latest one is this. Actually, we might later add a DB trigger that deletes the user's old image and then uploads the new one as well. So in this video, we're going to create two buttons in the profile section, a logout button and the Edit Details button. So let's do that. Alright, let's go to our text editor. And let's go to profile images. And here where we are not loading and authenticated at the bottom here after this div, let's add. So first, let's add the logout button, which is we've already we've already imported the logout user function, or action. So let's do that. So let's use it. So here, let's say, I'm going to surround this with a tooltip as well. And the title of the tooltip will be logged out. And the placement will be at the top. And here we're going to have our icon button. And the onClick for this on click is as cold as this thought. We call it handle logout. And let's close it. And inside of here, the icon that I'm going to use is called keyboard, keyboard return. And it's going to have a color of primary. Let's close the tag unless there's an error her nights Fine. Let's bring in the icon. So here on the icons as to import keyboard, return, oops, import keyboard return from material UI slash icon slash keyboard return. All right, and this handle logout let's create that so handle log out. It's actually just gonna call this this dot props dot log out. user. All right, did we actually add that to our? Yeah, we have that we have that here. We've imported it. And it should work fine. Let's save. Let's look at our app. Did we get an error? Now cool. So we get this error back and click it we actually get logged out. Let's look log back in. So the user at email, comm 123 through six. All right, we're back in. Now let's create a button for editing these details. And for this, I'm going to use the the dialog for go to component demos dialogue. Let's try this one. Not this one. The one with a form. Yeah, this one. So we're going to have something like this A dialog that has three fields, one for the buyer, one for the location and one for the website. And if we do like it's going to be saved instead of subscribe, and that will send a request to our server. And the way dialogues work is that you're going to have a button or a button at the top. It's this one that triggers the dialogue to open and then you're going to have the content of the dialogue. But since this will have a lot of code, let's actually put it in its own component. So here under the logout button, let's say let's add this component called edit details, which we haven't created yet. Let's go up here and it's important To end, so added details from we go back one level, we go to components, slash edit details. Alright, let's go to components. Actually, it's in the same directory same is on the same level. So just do like this. So here, let's create a new file called edit details, dot j s basketcase, of course. And here, let's do RC tab. Again, come on, there we go. Let's remove this export. Let's take these three imports, because we need them. So we're going to need fragment as well, any prop types. Let's, let's do a styles here. const styles is we're going to need the global theme. So stick the global theme and return. Let's just spread the theme for now. We need to add anything we're going to add it later. And we're going to need Of course, Redux to get our details from the server and actually show the values on that form. So let's say import connect from react, Redux. And we're also going to need an action that we haven't created yet, let's actually create the action first, not data actions in user actions. Let's go to the bottom here, as to export const. And this is going to be the function that sends a request to edit our details. Let's call it edit user details. And you will take user details. I knew it needs dispatch. So let's take this patch as well. And here we start by dispatching an action with the type loading user, is it Yeah, it's loading user. And here we send our request. So axios dot post, and it's going to be to slash user is going to take the user details, object, not post them. Here, when we get our response. Actually, we don't need the response, because we're just going to call get user data from here. So with dispatch, get user data. And here's the catch if we have any error, let's console log it. Alright, this is done. Let's save this. And here, let's bring it in. So import the user details from the go back one level Redux slash user actions, slash, not just user actions, actually slash actions, slash actions, slash user actions. Alright, let's connect our component. Let's cut to this edit, edit details. And I'd say export default Connect. And we're gonna have map state, to props to props. And here, we're just gonna have one action. So let's do an object like this with the action edit user details. And here let's do with styles. We pass in styles. And then for the second one, we pass in our edit details component. Alright, let's create our prop types as well. So let's do edit. Details. Prop types, equals, the first is the function so edit user details is a prop types dot func that is required. We're gonna, we're gonna need classes as well. Prop types.object.is required. And I think this is it. Yeah. Okay. So, here, we're gonna need to initialize the state. And in our state, we're going to have three fields bio, which is going to be initially an empty string, website, an empty string and location, an empty string, we need a Boolean for open, which is going to be initially false, because by default, it's it's closed the dialog. And here what we need to do is that we need to once this component is rendered, once it mounts we need to get the details from that we have of this user and put them as the values of our input. So let's say if our location says Los Angeles, California, we want to when we open the dialog in location, it will be already written there so that the user can edit or change And if we don't have anything, of course, it's going to be empty. So here in component did mount. Actually, we need to create our map state the props, const map state to props, it's gonna, it's gonna be a function that takes the state and returns the following, I can actually get credential just credentials we need. So we do create done shows, it's going to be from State DOT user dot credentials. Alright, so here, in component did mount, we need to do this dot set state, we need to set the bio. And we could actually in our credentials not have a bio, so we need to check for it. Otherwise, we're going to set it to undefined. So what we need to do is we need to do this dot props, actually lets the structure the credentials, const creed done shows equals this dot props. And here, what we need to do is that we need to say credentials dot bio. So if we have, so a ternary operator like this, if we have done, we have a bio, let's say. So we just say that again. So the value would be this, else, it's going to stay empty. So let's copy this other comma, space that paste it twice. So let's replace here Ctrl, D, and say website and control D and say location. All right, so when the component is loaded and mounted, it's going to set these values. So let's create our, our dialog. So here, instead of this div, I'm going to use fragment. Oops, it didn't close. Did we not bring it in? We did that Oh, why didn't close to. So fragment. Alright, so inside the fragment, so first thing is going to be our button, which is going to be inside a tooltip. And the title of the tooltip is going to be edit details. Placement as usual, on the top, I don't know why these tags are not being closed, is it because I didn't import them? I think because I didn't import these things. Let me import stuff that we're going to use. So import tool, from material UI slash core slash tooltip. Let's copy this, we need icon button. Actually, we can just bring in some stuff from here. So let's just bring in all this stuff until here. I spaced that before. So we're gonna need this icon button. And we're gonna need the edit icon. So say import edit icon from material UI slash icon slash edit. I'm here I'm just gonna say icons. Here. I'm gonna do Redux, oops. Redux stuff. And here, say movie stuff. Alright. So now, if I do this, yeah, closes the tooltip. And here we have our icon button. icon, button. The on click. Let's call it handle open. And let's give it a class. So I know we're gonna need to style it later. of class classes dot button classes. Actually, let's destructor classes as well. So let's do const classes, equals this dot props. Let's close this. And inside of here, we're going to have our icon which is the edit icon with a color of primary. Let's close it. Actually, let's create our handle open and handle close functions. So let's do handle open is takes nothing and it sets the state to open. So open will be true. And actually here as well, we need to get the details. We need to do this. But let's make this into a function of its own because we we don't want to repeat our code. Let's call this set user details to stay Or map makes more sense. And it takes the credentials because we need them. And here, let's face this and it. So here, we get the credentials, and we call it with credentials. And here as well, we need to call it. So let's do like this, I can just pass it this dot props dot credentials. And it will do the same. Let's create the handle close. Takes, yeah, it takes nothing. And here we just say this dot set state. Open, is false. All right. Thank you, this is it. Okay, so here, we need to, after the button, we need to put our form. But here, let's create, let's actually do the dialogue. And the dialogue will take the open, the open would be this dot State DOT open. And is the on close callback or font method, this would be the this dot handle close. And I'm going to give it a property of full width, which will make it take forward. And I'm going to give it a property max width of SM. If you see there's a cool example here, let's close this, the full width dialog and if you change here, you can actually customize the width. So I'm going to do the SM It seems the most you know, the one that makes the most sense, or the one most appropriate or for application. Don't know why these tags are closing, let's close the dialog. Pretty sure I imported the dialogue. Yeah, did excuse my text editor guys. Alright, so here we need the dialogue tech title. So dialogue, title. And this will say Edit your details. And under under here we put dialogue content. All right, close this one cool form. And here we'll have a form. And but it's not going to have a submit action because our dialogue actions are going to do that for us. So here we're gonna have text fields. So I'm going to have text, I'm going to save text field. And I'm actually no need to give it some properties. So first, we'll have the name. So the first will be a bio will have a type of text, have a label of bio, capital B. And I'm going to give it a property of multi line, which will make it a text area. Because this is a bio, so we'll need some some more space, and we'll give it three rows. And let's give it a placeholder. Like they will work like a hint. So here let's say a short bio about yourself. Let's give it a class name of classes dot remember we have access to our global theme. So we can do classes dot text field and it will style in the same way the signup and login text fields are styled. So it will give it a value as well with this will be this dot State DOT bio. And an unchanged which we haven't created yet will be this.on change. And let's give it full width. So it takes up the full width. And we close this as copy it and paste it two more times. But from these two, let's remove the multi line and the three rows because these will be just normal text fields. And this will be website. And the label is website. And text holder will be your personal slash professional. Professional I can't spell website. This dot State DOT website and same for the rest and here will be the location so location is the name. The label is location with a capital L. and here let's say let's just say where you live. And here let's say dot this dot State DOT location And yeah, that's fine. Let's create the on change. Actually, it will be a generic on change that we have already written. So let's just copy it from, from here from the login or from the signup. But did we say this will be actually let's call it handle change, change, because you want to stick with the same names that you've used across the same project. So that it makes more sense. So let's face this handle change here. And we also need at the bottom here, we need our actions or dialogue actions will be outside the dialogue content. So here, let's say dialogue. Actions, which will be the buttons at the bottom of the dialog, and we'll have two of them. So the first one is a button, and it has an onClick. And this will be the close button. So this dot handle close. And this will be the button if people want to cancel, let's give it a color of primary and let's call this cancel. And let's copy it, paste it, this is this will be the save. So this will be the one that sends the request. And let's give it the handle submit, which we haven't created yet. Okay, so we have handled change, let's create handle submit, will be handle, submit, it won't take an event because it's not based on a form. Let's do const const, user details equal to get the bio from this dot State DOT bio. Let's copy this twice. This will be website. And this will be location. And here we just need to call our function. So this dot props, our action edit user details and pass it our user details. And here, we actually close the dialog after we submit so this dot handle close, I guess. And I think this is it for this dialogue. Let's remove this dialogue text because we don't actually use it. And let's save all files and look at our app. Okay, map user details to state is not defined. Map user details to state it needs to go before the other ones. So that they will know what we're talking about. Oh, silly mistake, this dot map user details. All right. Let's look at our app cannot resolve icon edit. Its first of all edit icons. But either I or just edit. Yeah, I forgot the slash. Alright, so we get the edit button. So let's say I wanted to change London, UK to let's say Paris, France, and I wanted to remove Hello, um, user and say, I don't know. I am the user. So let's save loading. Cool. We got the new details. Paris, France, and I am the user. But I want this button to be on the right so let's go here under theme. Let's see button. I gave it class button I think Yeah, we did. So we simply gonna say float. Right? And we save. Cool. We got our button on the right and it says Edit details when you hover it and it works just fine. For remove this text we see our placeholders. Yeah. Alright. So right now if we log in the, the navbar doesn't change, the buttons still remain the same. So let's actually change it so that when we are authenticated, we have buttons here to add a post and to see notifications and stuff. Alright, let's go to our project. And here in navbar. The navbar now needs to know whether we're authenticated or not. So it needs to connect to the state. So let's bring in so here let's import import connect from react Redux. And let's connect our navbar. So here export default Connect, let's say map state to props. And it doesn't take a mark. It doesn't use any actions. So we just admit to that argument. And here let's say const. Map state to props takes the state And returns the following. So we need authenticated so we can extract only that so authenticated. That's going to be from State DOT user dot authenticated. All right, let's, let's ram prop types as well, I might as well. So prop types from prop dash types. And here, let's say dot prop types. We have authenticated, not state prop types, dot bull, because it's a Boolean, and it's required. Alright, so here, now that we have the authenticated, let's extract it. So inside the render, let's say const. authenticated equals this dot props. And inside the toolbar here, let's cut this, let's say let's do an expression and say authenticated. So ternary operator, if it's for authenticated, we show something on here, colon, so else, we show this. And because there's three elements here, we need to wrap them in a fragment, so frog meant. And we need to actually import that. So inside of here, let's paste our buttons. And let's import fragment here, add fragment. and here if we are, if we're actually authenticated, let's do another fragment here fragment tab. And here, we want to show three buttons. One, that's actually a plus. So here, I'll do of course, with the tooltip. We're going to use the same pattern from this button here. So tooltip icon button. But actually, there is like a bunch of elements here, let's create a component for this button that so that we don't actually have to import all these things into our components whenever we want to use this button. So let's create a custom component in utils. Let's create my, my button, dot j s, you can call it whatever I chose to call it my button. This is a functional component. So RFC tab. And here, we can just say export default, like this, and we're gonna destructor from the props is going to have children. So the way this thing works is that let's go back here. So the way it works is that it's going to take a tip, so for the title of the tip is going to take the onClick. And in case we need to style the tooltip or the icon button, we're going to take two class names for both of them. Of course, we don't have to have them, but if we do, it's going to style them. So here, we're going to take children and children is going to be whatever that's inside. And usually it's the icon. So we're going to have my button and then we're going to give the props and inside of that we give any icon and that icon will be will be the children will be rendered inside the button. So we're going to take an onClick we're going to take a btn class name, which is going to be for the icon button, we're going to take a tip class name, which is the class name for the tip for the tooltip. And we're going to take a tip as well, which is the title for the tooltip. And here instead of doing return like this, we can actually just do parenthesis, because we don't need to process any logic here. And here, we'll say tooltip it's actually important, the tooltip and the icon button. So here import tool. From art. Yeah, I'd like this material, UI slash core slash tooltip. And we need the icon button. Material UI, slash cause slash icon button. Alright, so here we say tooltip. With the title. That's tip, class name of tip class name. But of course, this is, if we don't give a class name. It's not a problem. It's just not going to have a class. So we can have it like this. And inside we'll have icon button. We'll have an unclick of on click and a class name of btn. Class Name button class name. And actually, let's do this because we're going to have stuff inside of it. And here will be just children which is going to be the icon. All right, let's save this Let's go to nav bar. Here, let's import it. So let's do over here at the bottom here to say import my button. From we go back one level to utils, slash my button. And here, instead of tooltip, we do. So this will be the plus button my button. And it's gonna need that, it's not going to have an onClick. Right now it's not going to do anything. So we just give it the title of the tip or just tip to say, create a scream, or post, a scream. And inside is going to have the Add button or add icon. Let's say here icons. Actually, I'm going to bring all the icons we need right now. So we need the Add icon from material, UI slash icons slash add. And by the way, this is the Like I said before, this is a default export, you can just have ADD, but the fact that I add icon to it makes it more readable in my code, I'm like, Okay, so this is an icon. Or let's copy all of this as paste it twice. And here, we're going to have Home icon. Here, this is going to be home. And here, I'm going to have notifications. From notifications, or Alright, here, we're going to have the icon, the Add icon, so add icon. Let's give it a color of primary. Let's close this. So that's the first button. The second one is going to be the home button. So my button and tip will be home. Will we have a class? No, I don't think so. So here we'll have the icon. So Home icon, color, primary. Actually, this is going to be a link to home. So let's wrap it in a link. Let's cut that and do link. We already imported link, let's do two, slash and close this. And inside paste our button. And the third one is going to be the notification. So let's say my button with a tip notifications. Let's close this. And inside we're gonna have the notifications icon, the color of prime primary. Alright, so with afueras dedicated, we should see these buttons. Let's save. I'm already running my project. Let's refresh. Oh, actually, the tip is not showing and the color shouldn't be primary, of course, don't always think in the because it's going to be the same as the bar. But the way these buttons work, they're actually svgs. So we can actually target them from our CSS. So let's go to our app CSS. And inside of here, I'm going to say and, actually, this is not sass to CSS. So I can, I need to say dot nav container. And here I'm gonna say SVG. So any SVG inside of the container and the nav container, so any SVG inside of our navbar. Let's give it a color of hashtag fff, which is white. Let's say let's go back. Cool. They're white now. But let's fix this notification. This the text not working. It must be from the button here. So tooltip or title, not title. I misspelled title. So let's save. Alright, so we got our tooltips. And if we click on a user, and we click on home, it actually redirects to home. Of course, these don't do anything yet, but we will fix that. That's actually changed as well the buttons and so in profile here, instead of this, we're going to have my button so as to my button. And it's going to have a tip of edit profile picture. And we're going to have an onClick of this dot handle edit picture. And because this button has a class name, we're going to give btn class name equals button. And yeah, this is it. And inside the my button will have the edit icon. Actually, I forgot something inside the knob bottom, we need to remove this color primaries, because they're they don't serve any purpose right now. So back to the profile here, we actually need the color primary. So primary, we closed the icon. Don't know why there's this squiggling. Okay, it's fixed. So we can remove this. And let's copy all of this. Let's come here under this tooltip. Let's do so the tip will be logged out. The onClick will be handle logout. And we don't need a btn class name here. So let's remove this. And this will be keyboard I keyboard, keyboard return instead of icon, we can remove all this now. And we need to remove the inputs because we don't need them, because they're already in the button. And we need to bring in the button. So here to say, import my button. Oops, button from utils slash my button. Oops. That's fine. Let's go to the details. So let's remove tooltip an icon button. And here let's bring in my button. So my button. Again, I did this you capitalized. So we go back one level slash shooto slash my button. And I think I still have it copied on I don't. So I could just say my button. And the tip will be edit details. And on click will be this dot handle open. And we need a btn class name. Classes dot button. And close this tag inside we have the edit icon with the color primary. Close this remove this. Let's copy this. So actually, no, this is the only button we have here. So let's just save all files. And let's check if nothing is broken. Cool, this still works. And we get the message where the placement is actually at the bottom. So here, I forgot to add the placement. So in the tooltip place, placement equals top, as you guys wanted on the bottom, you can leave as the default. I like the top one. And even here, if there's no space, it's going to be on the bottom, even though that actually says placement top and then the other one's going to be on the top. Alright, so now we want to show the like button and number of likes and number of comments on the screen cards. But one thing I want to fix is here in the home was the home here. So in the home, we're still using axios, we need to create an action for getting old screams, we need, we need to create actually a couple of actions that we're going to use as well in the scream components. So here I'm going to import some types. So we have set screams maybe some of them we haven't created yet. But we will in a second. So loading data as well. Like screen. Unlike screen, I think that's it. Yeah, that's it from we go back one level, and it's types. Of course we need axios. And here we needed to do the first one is the one we need in home. So export const get screens. Equals doesn't take anything and it just first dispatcher say loading. Oops, we need to use dispatch. So here we say dispatch. And here we say dispatch an action with the type of loading data like this. And then here we can send our requests. So axios get to slash screams and we get our result we dispatch an action with the type set screams and the payload will be the response data. and here if we get any error we need to clear out the screams Actually, we don't need to type for this, we can just dispatch type will be the same actually set screams and the payload will just be north. So just reset them back to No. Or are actually empty object, well, this will almost never happen but, you know, you never know. Alright, so let's put some comments here, let's say get all screams and now we're going to create the, like a screen, okay? So like a screen like this, let's say on like a screen okay here in the types, let's create these new types. So what do we have we have. So we have set screens loading data like screaming, unlike screen. So these are all data types or data reduce the types. So here we say const or export const, set screams equal set, screams not scream set screams we actually need another one for way later forgetting one screen that's called just set screen without an S. We need us control D here and do like screen. We need unlike screens or control the on oops, unlike screen. And what else we need loading data, which is going to be a UI thing. So here we paste, select this control the loading data thing this is it. Yeah. Okay, let's do the other actions as well so that we don't have to return to this file. So export const like scream. And this will take the screen ID of which screen to like, we'll take this batch. And first thing with dispatch to dispatcher loading No, actually, we don't. Let's do axios dot get and do template string slash scream slash dollar sign curly braces scream ID slash like. And then forget a response. We dispatch an action with the type like scream, like screen. And the payload will be rest data because we're going to get the like back. and here we can see catch. We have any errors, we actually just console log them. console log error. All right. Unlike scream I think is almost the same. We can just copy and paste it here. So unlike screen, it takes the ID. And it does the same a sends a request to slash scream slash ID slash on unlike. And here we get the data we dispatch a type of unlike scream. And yeah, it's the same. So it's good like this. Alright, let's go to the data reducer. Let me close the console window actually is taking up unnecessary space. So we need some types of set screen. When it actually screams we need like screen. We also need unlike screen. What else loading data? Yeah, I think this is it for now. So types, and we need to initialize to do an initial state variable which will have screens. So this will be the array that holds all screens whether in the homepage or in a user's page. And we have a singular screen, which will be one we want to see just the details of one screen and we will have a loading as well. She's initially set to false so export default, whoops default function that takes a state which is equal to the initial state initially and an action switch. Same thing as the data reducer. So action type. And here first, let's take care of the loading case. So loading data before loading, we just return types of return, we spread the state, and we set the loading to true. Next case will be the set screens, set screens, we return spread the state. And here are the, we set the screens to what we get. So action dot payload. Remember here, if we get the screens here, the response to data which is in the payload will have the array of all the screens. So we do screams action, not actions action dot payload, and we set the loading to false. So next will be the like scream. So case, like screen. So in this case, what we want to do is let me look at the Redux here. So what we want to do if we go to Redux, we go to our state, the way we determine whether we like a scream or not, we look at the likes array. And here, what we want to do is that if we like a scream, then we add that like to this array here, for the user. And we also add the number of the soda, the light count, let's say the screen has a light count of two, we add three to it. Or actually, no, actually, we get the entire screen back once we like a screen. So we just need to find that scream in the scream array. Or is it? Why don't we have screams here? Or because we didn't actually have that we don't have that reducer yet. What am I saying? So when we have the scream array, we will add the number to that screen, you'll you'll see, when we start testing it. I should have explained that later, actually, but whatever. So let index. Now we want to find the screen. So let's say State DOT screams dot screen dot find index, we need to find the index in the array first. And here is a higher order function. So this scream, we want to find the screen that has the scream dot scream ID the same as the one we got back from our payload. So. So if remember, when we like a scream, we get a screen, we'll get to that screen back. And then now we have to find it an increment, it's like count. So now we get the index of it. And what we do here, we do state and dot screams. And now we use the index equals action dot payload. So we replace it in the state. And now here as well we do state and for the unlike screen, actually, actually is the same even when we are like we get a screen back with the different, like count. So we can we can do this we can chain unlike scream like this. Yes scream like this. And this will that means in both cases do the same right here. And we need as well to handle like scream and unlike scream from the user reducer as well. So here, let's import the type. So like ups, like scream. And here. We do case, like and here they are actually different like screen. Here what we want to do, we want to add to that like so we can have this cap keys annoying. Alright, so we return the state as it is. And here in the likes array. We return an array and we spread State DOT likes. And we are the new ones. So here we add a new like and it will have a user handle just like the other likes, would have the State DOT credentials. Because it's this user so we can use the handle from the end it will have a screen ID of the same screen ID of the screen that's returned from the pay in the payload because after all, we return the same screen from our server or from our Cloud Function. And here let's see case. Unlike screen Now here's different, we just need to remove it from that array. So here we do return return, we spread the state. Here, we do likes, equals State DOT likes dot, we'll use filter to remove one of them. So here what we need what we need to do we say like, so we filter out any like, which has a scream ID, which is equal to the action dot payload, dot scream ID. Alright, so we're done in the reducers. Now we need to go to our screen and actually show this like button. So here, we need to actually reconnect our home. Actually, we need to connect our home. So here, let's connect our home first. So here import, connect. From react, Redux, we need to get the get screams. From Redux actions, data actions. Let's get prop types. And here, we need to connect the home. So Connect map state to props. And here we have only one action so we can put it here. So get screams. And we wrap this home in parenthesis, and here we say const. Map, state to props. Takes the state returns the following. So we need we need the data. So data is state data. Remember, this is our reducer our data reducer puts all the data in this data object. So we need to get this in the home. And we need to do our prop types. So home prop types equals we have our get screams she's a prop ups prop types dot funk is required. And we have data, which is a prop types.object.is required. All right, so here, we don't have a state because we're going to get them from the props. And here when the component mounts we just need to call get screams asexually get screams not get scream here. And Yep, that's correct. And here we get in the render. We get our screen screens rather. So from data we get. Or actually we can do like this. So screams and we need loading as well. equals this dot props dot data. So here, we do. So we check we don't check the screams we check the loading. And here we do just screams like this. And we don't need this parentheses actually. And here we don't need these parentheses as well because it's one element. All right, so this should fix the home. And actually our app is crushed so like scream is not exported because we didn't save save here as well. assignment for function call is that homeland 14 home Oh, yeah should call the function. Data reduce action is not defined and stay is an undefined Yes. So Oh, here it's state and action. or his action not actions. Yep. Okay. Okay, unlike scream is not defined in user reducer. Because we didn't actually bring it in. Or I didn't bring it in. Come on. This time it works. Oh boy. Data return undefined during initialisation. Oh, because we don't have a forgot about the default actually. This switch default case So default would just return state. All right. Okay, this is loading. Let me reload, just in case seems to load forever. But if we check the state, we actually have the screams. So must be some problem with the logic here. Oh, actually, no, if we're not loading then show the screams. Alright, cool. So again, the screens, everything works fine for home nuts. Now let's take care of the likes the like button. Now here and actually, first let's connect to the component. So here we connect from react. Redux. And we need like an unlike so like, scream, and unlike scream from Redux actions, data actions. And let's get prop types. While we're here. Okay, so here, let's do, let's cut this and say Connect map state to props and map actions to props. And here, we just paste that here, let's say const. Map state to props, equals takes the state and returns we need the user not the state to use a map map actions to props oops actions to props for now, just the two that we have. So like scream and unlike scream and we do the prop types. So we have like screen is a prop types function that is required. Let's actually copy this oops, hurts just unlike and we have user is prop types.objects.is required. We have scream, which we actually have been passed here this one prop types.object.is required. We have classes because of with styles. Alright. So here after after the body, I want to put we it's going to be we're going to depends on our authentication state, we're going to create a different like button so like button, as well whether we'd like to scream or not and after the like button or put a spawn with the number. So here we'll have like, count and says likes here. So the number of likes next to it the word likes. And so while we're here, actually we can put the I need to bring in my button, we can put the comment ones as well. So here we have a tip that will say comments. And actually doesn't have any doesn't do anything. But here we'll have a chart icon which I need to bring in as well with a color of primary color. Primary. Yep, let's bring in this actually is actually as well after this is to say how many comments there are. So here we say comment, count and space comments. And so we need to bring in my button and shut chat icon. So here is to import my button from utils slash my button and what else the icon so here let's A icons. Here let's actually Redux space here we have import shot icon from material, UI slash icons slash, shot. And here this, we need to create this like button. And the way we're going to do this is that we need to actually find out whether the user, this user that's logged in, has liked this screen or not, too. So I'm going to use these two icons. So if the user has like the screen, you see this filled heart, if not, you see this empty heart. And as well, if the user is not logged in, you see this empty heart. But when you click on it, it redirects you to the login page. Because you're not logged in, you can't like screen when you're not logged in. So here inside the component, I'm going to create a function called liked screen, which will tell us what whether we've liked this screen or not. And it takes a scream ID. Actually, it doesn't need to take the scrim ID because it only works for this screen. So it can do like this. And it checks if, first of all, we need to check whether we have a likes in our user object. Because if we don't, that means we don't even need to check it's false. Is there is no like there if there's no like array. And of course, if we don't, yeah, okay, let's do this dot props. I don't know, I was gonna say that, and then I'll stop. likes. If we have this array, and that and this array as well has this screen. So we do this dot props dot user dot likes, and we're going to need to use find the D array, higher order method or for forgetting, like, so we need to find a like with the like, with this scream ID. So which equals to this dot props, dot, scream, dot scream, ID, because remember, we have this, this screen, we have it passed down from the home. So this condition, find returns undefined if it doesn't find anything. So if it doesn't find one, the condition is false. So here if it's if, if it's if this is the case, then return true. Else. return false. always save. So this will this will check if we've liked the screen or not. And we'll have now two functions for like methods for liking and unliking. And by the way, if you're wondering why I'm like saying method instead of function because we're inside of a class, technically, a function that's belonging to a class is called a method, because it operates on that class alone. So this dot props dot scream, yeah, we just use the slike scream, and we pass it the ID. So that scream Id let me just copy this because unlike is almost the same, but we just changed this to unlike scream, you change this as well. Alright, so here, let's create this button. So inside of the render, let's say const. Like Button equals, now we're going to have two ternary operators. First thing is we're going to check if not authenticated. Actually, we need to get authenticated as well from the props. So here in the props, we have the user because we mapped it from the state. So we do user from the user we get we get the likes, don't think we get the likes we get authenticated. Think we only get authenticated. Yeah. So if not authenticated, then what we need to do is we need to show a button, my button. Tip also, like and inside of this button, we're gonna have a link. I'm not sure do we have it? Yeah, we we have link important so link to slash login. So if we're not logged in, it's gonna redirect us to login or we're gonna use favorite icon or fav not actually is the owner be the empty one. So favorite border. So yeah, this is called favorite border and the other one is just favorite. So we show favorite border with the color of primary. And yeah, we close this. It's actually important those two icons so we can just copy This. And here, replace chart with favorite, because I want to call the favorite one favorite icon, spaced again. And here, Alt and select these two and say, a favorite border. Alright, so now we have to both the icons, we can use them. So yeah, if we're not logged in, we show the empty heart and we flick off, click on it redirects to the homepage, I mean to the login page. Else, if we are logged in, we need to do another check now. So our check would be this dot liked scream. Oh, actually, I called it scheme apparently. So like scream. So like screen. So now if it returns true, that means we have liked this screen if it's in our likes array. So we need to show a full heart. So here we say my, my button with the tip. Now because we've already liked it, the tip should say undo like, and we're going to have an onClick for this. So on click will trigger the this dot unlike screen. And yeah, we're not going to have any classes. And here we're going to have the favorite icon with the color of primary. And here, let's copy this. Else. So if we haven't liked it, we show a button with the tip like and it triggers like scream. And the icon here would be favorite border. So favorite border. All right, let's save all of this. And let's, let's see if this is working. So let's go to social ape. And there we go. We've actually apparently liked all the screams, look at our status, put them side by side like this. First of all, let me log out. And yeah, we get an empty heart. And if we press on it, it redirects us to login as login. So user at email. COMM 123456. So here we have three likes, we've liked all the screens, and if I unlike this Hmm, there's something weird with these. Oh, okay, so it's removing the wrong ones. It's removing the other ones instead of removing just that. So think, okay, so in the US, okay, here Yeah, if I unlike a screen, it should filter out the one that is not equal. So it, it should just leave the other ones that are not equal to that one and remove. So filter filter removes these one keeps these ones not removed, this one's okay, this should fix it. Alright, so if I refresh, if I like, call, it shows the number and if you click on like scream and click on difference, that's what it did it incremented the light count of that scream in the screams array. And added dislike to our users like array. And it will do the same here to like, click here different shows you just the difference between the stage and the last stage. And if I unlike this, the unlike screen action, yeah, decrements the light count here and removes the like from the likes array. So let's now add a delete button for deleting our screams. Alright, so in the scream.js component, let's add the button under the handle right here. So under the typography that's got the handle, actually, it's gonna depend on a couple of things. So let's do here, delete button. And let's create this delete button. object. So here, let's say const. Delete button equals, and this is going to depend on whether we're logged in. And whether we are the owner of this screen. We don't want to show a delete button on this screen because it's not users scream. We're going to show the button on this and this and this one. Alright. So here we say, authenticated. So we need to make sure that we are authenticated. And user handle, which is the handle of this screen, the user handle of this screen equals, actually, we need to bring. So from here from user, we need to bring in the handle of this user, the current authenticated user. So it's inside of credentials. So here we do credentials. And from credentials, we destructor, the handle, which is handled. And so here, let's say how user handle equals handle. And here, let's say render this, or actually, it's a ternary operator. Because if it's not, we need to say no. So it doesn't render anything. So here we, we need to say, we're going to create a component for this with let's call it the lead, scream, like this. And actually, we need to pass it the scream ID of this current scream, because the Delete, scream component will not access any data from the state. So we pass it a scream ID of this scream ID that we already have of the screen. So let's create this component. So here, I'm going to create the lead scream, dot j s, let's do our sea top, remove this export. And let's bring in some of the imports that we have here. We're going to need us just copy all of this, we're going to need fragment I think we're styles, I don't think we're going to need link or none of these, actually, I'm gonna need my button. And I'm gonna need some stuff from the from movie. Actually, because this button is going to open up a dialog. So let's import we need button. Because the the option, the dialog actions are going to have buttons. So t y slash co slash button. Now we can just copy this, paste it three more times. Here Ctrl D, we need dialogue. Control the dialog title. We also need dialogue actions. We need the icon the Delete icon, which is called delete outline, you can also use the Delete which is full icon. But I prefer the the outline one because it doesn't. It doesn't distract too much from the screen itself. You don't want to emphasize the delete button in your design, so slash actually slash icons, slash delete. outline. All right here, let's bring in Connect. Because we need Actually, we need to create the the action for deleting a scream. So let's import delete, scream from Redux slash actions slash data actions. Let's go and create this. So here at the bottom, let's say export const. Delete. screen, it's got to take the screen ID. We need dispatch. And here we're not going to do we're not going to dispatch a loading, we're just gonna send a request axios to delete to backticks, slash scream, slash and we concatenate the scream ID that we got passed. And here we say dot then we don't need what's written in the result. There's nothing there's just a message. So here we say we dispatch a action with a type, which we haven't created yet. Delete, scream. And the payload is going to be the scream ID that we passed to the to the function, this one. So here, I say dot catch. error, we just console log it. This is it. Let's actually copy this delete screen. Important from types and let's create it and types. So it's spot of the data reducer. So here we say, export const paste Delete screen equals a string delete screen. Let's go to data reducer, or data reducer. And here, we handle the case. So let's say case, delete screen. Because the way this is gonna work is that what we can do, we can as well delete the scream and then call get screams. But I don't think that looks good. Because if you delete a scream, and then you again, show that all screams are loading, it kind of gives away that you're actually fetching the screens again. And plus, we actually send an extra request. And that's not necessary. Because the fact that we get a response here, that means that the screen is deleted, we can just delete it from the local state because we know that it's deleted on the server. So what am I doing this custom data data reducer, and here, we just need to find the index of that scream and remove it from screams. So here, we say, we can use the same index variable from here, it's already declared here, say index equals State DOT screams, dot find index. And we need to find the index of the scream that has a scream dot scream ID. That's the same as the action payload. This is why we passed that scream ideas action pedal. And now we say State DOT screams, dot splice, which removes which removes elements of a an array starting from one index, which is the index and a number of them, which is just one, we just remove that one. And here we do return and spread the state. Alright, so the auction is done. Now we need to create the component. Let's connect this and actually let's initialize a state's const styles rather, object. And here, let's say let's get this let's say, export Connect. Map state to props. And we need one action, which is the Delete screen. And here we connected to with styles. We pass the styles. And for the second one, we pass the component. So here let's do const maps date the props. Actually, no, we don't need anything from the state. So we don't need a map state to props. so here we can actually just pass No, we just need the action. Let's create our prototypes. So delete, scream, dot prop types, equals, we have the delayed scream function. So prop types.funk.as required. We have classes prop types, dot object that is required. Quiet. And we have the scream ID that we got passed down from from our scream called scream ID prop types.string.is required. All right, so let's create our component here. Here in the render, we need our classes const classes. This dot props. Here, let's do return. Wrap everything in a fragment. So here the first thing will be the button that triggers this dialogue to open. So my button with a tip. Let's say delete, scream, actually with space in between. and the onClick will be this dot handle open and the btn class name. Do you need a btn class? Yeah, we do we need to style this. Let's give classes dot delete button. Actually not like this. So we close the button like this. And inside the button we need to have the Delete icon. So delete. outline with a color of secondary wanted to be red because it's the delete button. Let's create these handler methods. So actually we need to set the state as well. Because this we need an open very an open Boolean which is false by default, we need a handle open. She takes nothing and does this dots setstate. Open true. And we can just copy this and say handle close. Sets date open to false. And we need as well. One called delete scream, which calls the function as the action this dot props dot delete screen. And we pass it this dot props dot scream ID, which was passed down from the screen. So where are we? Yeah, this one right here. So the scream ID, we passed it here. And then we set the open to false. So once we delete the screen, we close the dialog. Alright, so under the button here, we actually do our dialogue. So dialogue. And this will take a while we have yet to open, which is going to be this dot State DOT open. And the open close, which is this dot handle close. Let's give it a property of full width. Because I want to specify the width of this and give it max width. Small, SM, close this. And here we will have a dialogue title. And the dialogue title will simply say Are you sure you want to delete, oops, delete, I hate the word delete the scream. And you can as well add like a body that says this action like in between brackets like this action is not reversible, or guys like Feel free to customize what we're doing. Don't like if you want to add something you can. So experiment all you want, I actually recommend that you learn a lot by doing that. So we have now actions, we need to do our actions which are two buttons, one that cancels, which closes and one that says delete, which actually confirms the Delete and calls this delete, scream and closes the dialog as well. So the first one will be button on click. This is the cancel. So it's going to trigger 100 clothes. And just give it a color of primary. Yeah, that's an inside the button it will say cancel. Or we could just copy this and add a second one that says delete. And we'll call delete, scream. And the color will be secondary. We want it to be red. And I think this is it. Yeah, this is a you had the thing. Oh, we need to style this button. I want it to be so I want the button. Scream is on the phone and Data Register because we didn't save or think or did we not? We didn't import it. So delete screen like this. Where's the up? delayed scream is not defined. It is. So in scream delete. All I didn't import my bad. So here are the top, say import, delete scream from delete screen. All right. Okay, cool. So we get the button on this right here. But let's actually test this. Let's delete this another one. So we get a dialog that says are you sure if we cancel it closes the dialog. And if we click again, it opens it. If I click Delete, it's gone. And it's removed as well. Instantly from here, cool. But I want to place this button right here facing the user. So let's do so here let's add this delete button style. and here we can say left 80% or actually as a string 80%. We need to give this a positive position of absolute. So you can move it around. So absolute cool. Let's save look at it. Or is it actually it's right here. Oh, actually, we need to give the court a position of relative so that the absolute on the button could work. So here in the card. Yeah, this here Let's put it at the top, let's say position puts session of relative. Now it should this absolute and refer to the card. Cool. And it does. On let's let's set it right here, actually. So inspect this. And this button would be, yeah, this button right here. Let's remove the left because I want to align it with a some of the left for now. And then other top. So I want to align it exactly what the user here. So say top 5%. Actually, a bit more. Yeah. 10%. And then actually, the left should be maybe like 90%. As to 90. Yeah, perfect. It's, it looks much better like this. Alright, so here in the Delete, say left 90%. And then top of 10%. That's safe. Cool. We got the button on the may remove the inspect window, and we got the button and it works. we delete this yet another one works. Cool. All right. Yeah, by the way, guys, I will put a link in the description for the get get repository for this for all this code. And let me commit right now and show you how I've been committing this. Let me clear. So git add git commit. This is what part 24 I think. Yeah, it's part 20 as part 25, Part 25. Alright, so git log, let me show you how you can actually. So what does this get? Log? Yeah. Okay, so part 25 right now. And if you have, let's say you're stuck up, but like 22, or something, you can just do a git checkout and take this. So it's like, zero, a, two, five, or is that two zero, F. And here you have the code that exactly part 22. And I only recommend you to get the code if you're actually completely stuck. And you're like, what the hell, I typed the exact same code, but mine doesn't work in his works. You can just compare against yours. So that you see where you actually type something wrong or something like this. I mean, go back to go check out master. Yeah, so I will put a link in the description for the for the get repository for this code. So let's add some functionality to our post Screen button right here. So I wanted to open a dialog. And then in that dialog, we type our scream, and we press submit, and then it shows it right here. Here, let's create a new component, call it post scream, dot j s basketcase, of course. And here in the navbar. Let's replace this first button. Yeah, this one right here. Let's say post scream, close the tag is removed the Add icon, we don't need it anymore. And here, let's import the component we just created. Suppose scream from same level post scream. Alright, we are here. So this one is going to have a dialogue, it's going to need a bunch of things, very similar to the Edit details. So we can actually copy all of these and then edit it. So let's bring the Redux stuff down. I prefer to have it at the bottom. And we need Redux react component fragment prop types, all this stuff we need. We're not going to need auctions. I mean, remove auctions. And instead, not instead, we also need the circular progress. So So killer progress. I want to show a spinner one we are sending our request, cemetery UI slash core slash circular progress. All right, we don't need edit user details. Instead, we need post scream from data actions. And we need to create that in a moment. And here we say class, post scream, extend extends component. Here let's do export. Default Connect. We're gonna have a map state to props. And we only need one action. So let's say here inside this object post screen, we cannot get with with styles and we pass it styles and the second parameter Is our component post scream here, let's say const styles. Let's leave it empty for now. Let's do our prop types. So post scream dot prop types. Here we have post scream. Prop types dot funk is required. And we're going to need the UI. So say UI, prop types, the object that is required to map state to props const map state, to props equals takes in the state, and returns the following. So we just need the UI. So UI is state.ui. Okay, before we carry on, let's actually create the auction. So let's go to data auctions. And here, I'm going to put it under the get screen, let's put a comment, say post a scream. And here, let's say, export const. Post scream, it takes in new scream in his dispatch, as well, so we go through dispatch. And here I want as well. So we got that loading spinner, we want to show some loading. So let's dispatch a an action with the type loading UI. After that, let's do our axios call. So axios dot post, to slash scream. And we pass the new scream as the data. So that then when you get a response, here, we're going to dispatch a new one a new type. So this will be type, I'm going to call this post screen. And the payload will be the response. So restaurant data, which is going to be one screen. And here. Actually, let's do the catch first. So it would make sense. Because we can get some validation errors, if you remember, we could have an empty body and it will say like body must not be empty. so here if we get an error, we need to dispatch set errors. So type set errors, and the payload is. So error dot response dot data. And here Actually, let's dispatch a clear errors, just in case there is some errors. So type is clear. errors. Let me make sure everything is fine. So your post screen restaurant data, will dispatch clear errors. Okay, everything is fine here. And let me make sure we brought everything. So we need post scream, which, which I think doesn't exist yet in the types. So it's set errors and clear errors. And yeah, loading you Why do we have loading UI, we don't loading UI. Let's go to types and create the ones that we don't have yet. So for data, we need to say export const. Post screen equals post, scream. And we need loading UI is created set errors, we need clear errors. So let's say export const, clear errors equals clear errors. All right, so now we need to go to the data reducer and change the state accordingly. So here, under here, we say case post screen. So okay, let's bring in the type as well and actually both screen. so here if we get a scream, we need to add it to our to our screams array. So here we say return the state as it was. And in screams, we're gonna, we're going to actually put it at the top. So because it's the newest one, so here we do action dot payload. And then we spread the rest of State DOT screams. Alright, so we're done here. Let's save everything and let's go to our post screen and created. So inside of this component, we're going to have a state we have a dialogue. So we need the open So initially set to false, we need a body for our screen, which is empty, and potential errors that we can get, which is an empty object initially. So here we need handle open and handle close. Doesn't take anything, just this dot set state to open to true. Let's copy this and do the same for clothes. We're not the same, but we just change the value of open to false. All right, here we are, let's do our render, render. Let's get errors in case there's any from the state, oops, this dot state. And let's get our classes. And we also need the loading from UI. Actually, we need just the loading. So what we can do here, we can do in map state the prospect to say loading, oops, not like this loading. And it will be Yeah, we need loading. And here we'll say loading as well. And it will be the state.ui dot loading. So we get just that. Actually, no, nevermind, I'm wrong, because errors is stored in there. And we will need errors as well. Oops. Okay, so from UI here, we need loading. And here, we get these from this dot props will return gonna have a fragment that's gonna surround everything, and first is going to be the button that triggers this. So my button is going to have the onClick of this dot handle open. And the tip, oops, the tip will say, post a screen with an exclamation mark, because it's screaming, of course. And here we'll have a an Add icon with a color of primary. Or will it be a primary? I don't think it's going to be a primary because it's going to be blue. So we just say Add icon. And let's bring the icon. So here, let's do import Add icon from material, UI slash icons slash add. Here, we're going to have our dialogue. So dialogue. And here, we need a What do we need an opener? This dot State DOT open, we need an on close. She has this dot handle close. Let's give it full width, and a max width of SM. All right, here, let's stop. And let's say what do we need, we need a title first. So actually, I'm going to put a button First, I want to put like a close button on the top right. So let's say my button. And this will have a tip that says close. It's just I just wanted to show you like you can do this as well. I can do a Cancel button. But I just want to show you this style as well as have some variety. This thought, yeah, this close button as well has handled close when you click it. So it closes the modal oops, close the dialog. And let's give it a class name because we'll need to style this. And what do we call this? classes, close button. And inside of here, I think there is a close icon. Let me check quickly. Summary docs are shiny the material design. Yep, close, so it's going to be just close. So let's copy this and select our then Ctrl D and do Close, close icon. So here is a close icon without any color, leave it black. And here under the button, we need our title. So dialog title. This will say post a new screen. And under here we need our dialogue content. So dialogue content. And here we're gonna have a form Say on submit equals this dot handle, submit, haven't created yet. But we will in a moment, here we'll have a oops, what is this? Here we'll have a text field with a name, body type of text label of what do we say scream. Because why not? We're gonna give it multi line because this is going to be a text area. Let's give it three rows. So rows three, give it a place holder. And that's a, I don't know, scream, scream at your fellow friends, or apes, since this is social. And of course, we need an error. In case there's any errors. And here, the error is the the errors dot body, if you remember, we have that in our validation. So actually, inside the expression, we say, if it's true, then the true else false. Alright, so here helper text, which will show the error message. Text like this. And this will say we'll have errors dot body. Of course, if it's undefined, we're not going to have any text. And here, let's give it a class name of classes, dot text field, the global text field styling that we have classes, actually, to use the global styles, we need to take in our our theme sort of theme. And return this and then spread the theme here. So that we can use the global styles. What's wrong? All because this is not close. Okay? Think this is it, actually, when you're not the on change, on change. And we'll say this dot handle change. Say full with Yep, that's it. That's one beefy textfield. Here, we'll put a submit button. So button. And it's gonna have a type of Submit. variant of contained because that's the style we went with, we'll continue with that style, a color of none other than primary. Just give a class name of classes that Submit button. A disabled gonna do the same thing like the signup form. And the login as well disabled on loading, unloading. And inside the button, we're gonna have the circular progress. So let's say sir, killer progress. Let's give it a size of 30. I think the size does matter. Actually, as long as it's inside something it's going to be it's not going to be bigger than it but you can experiment and find out. Skip this the progress spinner class, because we need to make this we need to give it the position of absolute and give this the position of relative so that this would be centered within the button. Okay, so Oh, yeah, the button is to say, Where are we? So here? Inside the button, we need to say Submit. Yup, I think this is it. Oh, actually, what am I saying they're circular progress should only appear if we're loading. So here we do an expression I cut it actually and you say loading and and not this and and, and do parentheses and put the circular loading inside of it. Okay, so here and the styles. Let's style the the submit button. I give it Submit button you met Yep, submit button. So here let's give this a position of relative and the progress spinner. Give this a position of absolute and all the close button as well. We need to give the close button position of CIO position of absolute Unlike absolute, left is given 90% was 90, something like the delete button, guys. And the top. Let's give it 10%. And I think yeah, this is it. Let's see what this looks like. Just make sure we don't have any errors. And we do of course. Oh, we already had clear errors. And we removed that. Yeah, I don't know what that post screen was so stopped and run again and it didn't happen. Okay, so source selector is not a function. Okay, I added a pair of parentheses here by mistake. Okay, so for click on post screen, it opens up this modal call this dialogue. And if I submit, okay, reloads the whole thing. Oh, of course, forgot, right, the handle submit function, and the own change as well for that matter. So handle change will take the event. And here we'll say this dot said state. So we have event dot target dot name. And we set it to event dot target dot value for the handle, submit, submit to extend the event to event dot prevent fault. And here we use the post screen action so this dot props dot post scream and we pass it this object with the body. This dot State DOT body. Alright, let's save. Let's check it out. All right, this is our like dialogue. This is the close button. If you click it, it closes it supposed to scream. If we actually leave it empty, we send we don't get the errors. And it shook state roll. We do have an hour. Okay, I need to do use component will receive props and assigned error. So component or receive props. Next props. And here let's check for the error. So if next props.ui dot errors, we do this dot set state errors is next props.ui dot errors. All right, let's check a gun. So if we tried to send an empty call get an error. And if we say hello, and we click Submit, okay submits it. And we see which is cool, but it doesn't close the this what we can do here, but we still have the errors, what we need to do is that we need to check if there is no errors. And the loading has stopped. We actually from the component received props close the handle, mean close the the dialog so we can say here if not next props.ui dot errors. Because we clear the errors on success if you remember from the action. And next props.or we could just say and not oops. And not, not. Next props.ui dot loading. So if this is the case, this dot set state actually lets as well empty the body because otherwise if we open the dialog again, the body will have some text. So we put the body to an empty string. And we do this dot handle close. Yeah, which will as well. The handle close was well clear. Actually the handle close should clear the error. So here, we say we said open to false. And we set the errors to an empty object because if we don't, we're still going to see the errors. Okay, so here we get errors and we close it. Yeah, we don't get the errors anymore because we cleared the errors once we close it and if we submit now a new one I don't know why I saw that error for a second. All because there was already errors in the state, maybe I'm not clear on them properly. Okay, so we're submitting screens. Cool. So it works. And it instantly shows them here as delete them. Yeah. So yeah, we're done. A couple of things I want to edit about this model this dialogue quickly. This button, I want to align it exactly. Okay, let's put them side by side on align exactly in front of the title. So let's go here. Let me remove the left so we can align it let me adjust this. Okay, so 6% seems decent. And 90, or maybe like a bit more, yeah, 90. Yeah, 91. I also want some margin between the submit button and and I want to put the submit button on the right side as well. So six and 91 that added these values. So here, yeah, the left is 91. And the top is six, and the button on a given a property of float right. And some margin. Top think tanks should be fine. Let's save slick our app. Hope. Yep, the reloads. Okay, reload the gun. Alright, there we go. Cool. It looks much better. Now. I like the button on the side. One problem with this, though, that I didn't fix last video is that if I click Submit, and there's some errors in the state, and I close, these errors are still in the state. So if I click here, I don't see them, because we only received them using component will receive props, by file type something and I would submit will quickly see the error. And then it submits. That's not. That's not very cool noise. Let's fix that. So in the data actions, I'm going to create a function, let's call it export const. Let's call it clear errors, which does just that it doesn't take anything we it goes through this patch. And it dispatches the action with type clear errors, that's it just clears the errors essentially. And yeah, we have that type. So here, when we get when we close the, the when we close the dialog, we want to clear the errors as well, just in case. So we aren't clear errors here when we close the dialog. So let's bring it in as well. So clear. errors. Let's copy it. Let's add it here in our map actions to props. And let's add it as a prop type. And it's the same as this we can copy this colon and paste this. And let's Oh prop types not rock types. Let's save. Oh shit, I didn't mean to open that. Alright, failed to compile clear errors is not exported or because I didn't save all files and save all files. We go Okay, so we open post the screen will close it. Whoa, what is this maximum update depth exceeded there must be like an infinite loop or something. So handle clothes. So setstate under clothes and unclear ORS. Hmm. As no UI reducer, so clear set loading false, or is No. Oh, I see. There's an infinite loop here. Because whenever we call handle close, it calls clear errors, which sets the errors to know and loading to false, which triggers this again, which triggers handle close. So there's like an infinite loop. So we can solve it by here, instead of calling handle close, we can manually close without calling this function so that it doesn't loop. So we can just give it this. Actually, you could just copy this stuff over here. So yeah, we can close it without calling handle close, which shouldn't have an infinite loop. So if we open here, and we close, cool, it doesn't bug out. And if we type something and we get an error, oh no, no, we don't get nearby. Alright, so if you get an error like this and we close it. Now we shouldn't get an error once we submit. Cool and we don't nice, the errors are being cleared once we close the dialog All right, let's actually start working on the on the button that let us expand our screens and see all the details of one screen. Alright, let me close this dev tools. Let's go. Here, let's create a file called screen dialogue. Actually, let's start by creating an action. Because we're going to need the action that gets only one screen with all the details. So here, let's add data actions. Let's export const, get scream without s, so singular, and we pass it the scream, Id need this patch as well. And here for loading, I'm going to use the UI loading and not the loading that's inside of screams or inside of the scream. Yeah, the data reducer. So here, we dispatch an action with the type loading UI. And here we do axios dot get template strings slash scream, slash, we pass it that scream ID. And here, we do that, then I get a result. And we need to dispatch a new type. Summon to enter the type set screen without an S on imports that automatically and the payload is the rest of data. And here after we need to stop loading, because it doesn't, nothing changes the loading from the UI to false if we don't do it manually, first. So dispatch type stop loading UI, which we haven't created yet. And here we have any error. We What do we do, we just console log, I guess we'll never have an error unless our databases corrupt or something. So let's go to UI reducer and handle the stop loading UI. So case, stop loading, slow loading UI. Here, we just return the state as it is. And we set loading to false. So the opposite of loading UI, basically, let's copy this. Let's go up here. Let's import it, as do the same in data actions. Let's go to our types. And we have set screen, we only need to create the the stop loading UI, export const, paste, and paste again. Alright, let's go to our to our scream card. And here, let's import our scream dialog. Import scream, scream dialog from the same directory. And let's put it at the bottom. Right here at the end of the chord content. So screen dialogue, we're gonna pass it the scream ID so that it uses that to fetches the screen so that it knows which screen to get. We're gonna pass the user handle which we will need way later. Use a handle. Alright, we're done here. Let's close this. Let's close all of these. We don't need to use them anymore. Let's save this and close it. Make sure we don't have any errors we don't cool. Here, we're going to need a bunch of things similar to what is it to post screen. So let's take these, paste them here. We're going to need de j s as well to show when a screen was posted. So import day j s from day j s. We're going to need link to have a link to the user that posted this screen. So no react user what react router DOM and here we're going to need a bunch of material UI stuff which is let's let's copy from the the post scream this stuff the dialogue stuff. We need a copy from here to here. We don't need to add icon. So instead, we can just put a common a common saying icons. And here we need the grid, because I'm going to split the card into two sides, one side has the picture on size has the details from material, UI slash core slash grid. And we're gonna need typography, of course, typography. And we're gonna need the Redux stuff. So Connect, and we're gonna get scream. Let's create an empty styles. Array object for now, let's say class. Scream, dialog, extends, component. And here, let's do the prop types. So scream, dialog, prop prop types, we're going to have the get screen function. So a prop types.funk.is. required. We're gonna have the scream ID from passed down. So prop types.string.is required. We're going to have the user handle, we got passed down as well. Prop types.string.is required. And from the state, we're going to get the screen the object is required. And we can just copy this same thing for the UI, we need the UI for loading. and here we can do our map state to props to take the state and return the following. What do we need, we need the screen which will be in State DOT data dot scream. And we need the UI which is in state the UI. All right, when we're going to see map, action const map actions to props. For now it's just gonna have get screens get screen. I need to export the fault. Connect map state to props, map actions to props and who have passed with styles. Styles, and the second will be scream dialog. Alright, so in our component, so this is a dialogue. So we need a in our state, we need an open Boolean, which is false by default, we the handle open which sets the state open is true. Let's copy it, paste that change this with close and open false. All right. Actually, we need to call here when we open the screen we need to call the get screams because when we caught when we open the screen we need to when we open the dialog we need to send a request to our server to get our scream so we call the get scream and we pass it the ID this dot props dot scream ID that we got passed down from the scream card. And here inside of we need to create the render render inside of here let's get so let's do const let's get classes. Let's get the scream. And this will be because get scream is going to get us the scream and set it in our props as the screen because we get it from the state here. So here from scream are going to get everything so it's great scream ID we need the body. We need the credit Related art, we need the like count. We need a comment count, even though we're not going to use all of them in this video, but let's get all of them anyway, we need the user image we need, what else user handle? And after scream actually, why did I do a scream twice? Like this. And here like this after scream, we need to get the loading from you Why? So you why. And with the structure loading from it. And all of this equals this dot props. Let's save. So it formats. And here after we get all the stuff, we need to return a fragment. Why is it not closing? Come on, fragment? Oh, what am I doing this is inside the render. So inside the fragment first thing, of course, is the button that opens this dialog. So my button and the onClick will be this dot handle open. And the tip will say expand, scream. And we'll have we'll have to style it. So let's do tip class name. Let's say classes dot expand button. And Yep, inside the button, we will have an icon. This will be the unfold more. And with a color of primary. Actually, I forgot to import this. So here let's copy this and select this old select this and say on fold more. So yeah, we have the icon. After we put our dialogue, so dialogue, lock, close it, we can actually get the stuff from post screen. It's exactly the same. Actually, even the close button will be the same I think let's copy all of this. So let's go back here. Let's do this. Yeah, this dot state open handle close for with max width. And the button close has the onClick contact, close and close button as the class call. Alright, so here after the button right here, we put our content. So I say dialogue content. And let's give this a class name of classes dot dialog content. And here because we need to check for loading or not, let's say dialog, markup. And here after all this stuff, let's say const. Dialogue markup equals if loading. Then we're going to use our brought in the the circular progress. So here, let's say circular progress on this needs to be massive. So sighs let's give 200. And yeah, this is it. And also, if we're not loading, then we need to show me the grid container. spacing, let's give a spacing of 16. Why didn't close it, grid. And here we need items. So grid item. This is the site for the image. So I'm going to give it a width of five. So SM five. And here we'll put an image source will be user image. And the old let's say profile. And here let's say let's give it a class name because we need to style this image profile image. And let's copy this. Actually, it would have been faster if I typed it but whatever. Actually, maybe not. And here we will. First thing we need to show is the handle of whoever typed this in whoever posted the screen typography and then here we'll have a component link because this needs to link to the Users page. Karla primary, and here we give a variant similar to the scream card actually exactly the same variant of H five. And this will go to still backticks slash users slash, dollar sign curly braces, use a handle. And here, let's close the typography. Actually, no, let's close it like this, because we need to write stuff inside of it. And here's the art. And then we concatenate the user handle. I misspelled user handle here like this. Cool. After the typography, we need to put a horizontal ruler, but I need to click to style this. So let's call this let's call this I don't know, invisible separator. And let's go up here in our styles, I think we might, we might need the global styles. So let's do a steak theme. And then return and then spread theme here. And this invisible separator will have a border of non because a horizontal rulers, by default Have some water, I don't want to, I don't want it to be visible. And let's give it a margin of four. So it creates some space between our elements. So let's close this tag. And here we get our created art. We put one This one, this was when this screen was posted. So here, the variant will be body two. And let's give this a color. Same like the in the scream card, that color of text secondary. So it's kind of great to know why these tags are not closing again. So oops, inside of typography, here, stone expression de j s, and we pass it the created art. And we do dot format. And I've written this in front of myself in a piece of paper, let me check. So it's H, colon, dash, a, I mean space a comma, capital M, Double D, quadruple y. So this is the format of the date. And here we'll have another HR with a class name of classes dot invisible separator again. And here we'll put the body so say typography. And here, let's have a variant of body one. That's it. And here, we just put body. All right. This is it for now, let's save. Let's check if we have any errors. We don't. Cool. All right, so we get this expand button. And if we click it, we get nothing. Let's look at our state. Receive truffe one on Boolean attribute container. That's interesting. And here in our state, look at the data. We're not getting scream for some reason. Hmm, this dot props dot get screen. Oh, because in the data register, I forgot to handle the type. Or the Yeah, the type gets set screen. So here, let's say case, set, scream, scream like this. And here we need to Oh my god, no. Really, come on. Okay. Sorry about my cups, guys. So state and here we set the scream the singular scream to simply action dot payload. Let's save. And this time, let's check, we expand. Cool we get our screen we get all the details of our scream. And if we look here, in our state, in our data in the singular scream, we get this scream. So let me change the view to the tree. So yeah, we get that scream and then if we go to this screen, it will know here it will change to that screen. All right, so let's style the image. Because right now it's massive. In the dialogue dialog here in the styles, let me close the terminal. And here, the profile image, give it a max width of 200 or 200, not 300. And let's give it a height. Same 200, I want it to be circular. So let's give it a border radius of 50%. And us give it object fit of cover in case the ratio doesn't match the one by one so that it doesn't stretch it. And here as well, I want to style the content. Because right now all the oldest stuff is kind of going to the edges as well. It's too close to edges, I want to have some padding, so to push it a bit in. So let's do dialogue content. And here, we're just going to give it a padding of 20. Let's save. Let's go here. Let's, let's make this button go to the right. And now this is container. All right, so our grid is behaving properly. Now this button is to take to go to the right. So here we say. Close button. And what do is position? Absolute. And here we say left 90%. Cool, but some reason the padding is not working. So what is the padding dialog content? So class name equals class name, that dialogue content actually with lowercase d? All right, cool. So we're getting our details inside of the screen. And yeah, looks it looks okay for now. So here, want to fix some styling. Before we do anything, I want to bring this button to the right, so it's more visible. So let's go to scream, scream dialog. And we've actually given it a class, I believe, where is it? Yeah, expand button. Let's copy this. We've given it a class, but we didn't style it. So here, let's do expand button. And here, let's do position. Absolute. Let's give it a left of 90%. Let's see what it looks like now. we refresh. Cool. It's on the right now. All right, I want to move this button as well move it a bit down. So it faces the user. And I want to change the styling. By the way, you can go to Redux. And if you have something that's like going too fast, for example, the loading stage here, the loading UI, we can go back one level and just pause there and you can see your animation, or whatever you have, and you can style it. So this I want to bring it to the middle. And I want it to be a bit less thick than then what it is right now. So let's go to our code. And here. Where is it? So I'm going to put it in a diff? Well, we kind of have to so let's do div. And let's paste it in. And we're gonna change the thickness. This can take a value for thickness. I'm going to give it to and here the div will have a class name. And it will be classes dot scollard, spinner, Dev. And here. Let's do spinner div. Let's give it a text align. of center. So aligned to the center. Let's give it some margin on the top and bottom. So a margin top 50 and margin. Bottom 50. Let's see what it looks like. Here. Alright, we expand. us go back. Yeah, cool. It's in the middle and it's less thick. It looks much better and the button is a bit to the left now. Let's actually remove this just Yeah. Alright, so it looks much better now. Alright, so now what we want to work on is the action buttons. So this like button here and the common button which does nothing, but it's just an icon, and the number of comments and likes here as well the same as in the screen. So what I thought about is that since they're the same, we can go to the screen and this like button, or we can make it into its own component, because we will need it in the scream dialog as well. And one of the good things that you will do one of the best practices is to try and keep your components as small as possible. And I noticed the screen dialog will be really massive if we don't divide it into further components. So here in components, let's create a Like button, button dot j s. And here, we can actually cut this. Oops, bring it in. Let's do ice top. Here in the render, we can say return like button. And before that, we can say const like button, and we need to get authenticated from the state. So we need the user, we need a couple of things actually here. So we need my button. Because we're using it from the same level. Actually, it's in the youtell. Go back one level slash utils slash my button when need link, so import link from react router DOM. We need prop types. Of course, we need the icons that we have here. So icons, say import, we can actually just cut to these from here because we don't need them. So paste them here. We need connect from react Redux. And we need to bring the like and unlike auctions, we don't need the oops, we don't need them here anymore. So we can cut this line. We can go down here, we can remove them from the prop types. And we can remove this map actions to props for now. And yeah, let's save let's go here. Let's paste it here. And here, we're going to have prop types sold like button dot prop types. We we need to access the user to user let's say prop types.object.is required. We need the scream Id actually we were going to pass it down. So to say prop types dot string that is required. We need the two functions. So like scream, pro prop types dot funk that is required. We can copy this line and just add on here. And here we export the fault that's called this Connect map state to props, map actions to props. connected with this we don't need styles because we have no styles here can say const. Map state to props equals takes the state and returns we need the user state user we need to create the map oops map actions to props. So we'll have the like scream and the unlike on like scream like this. So here the same actually we need to cut to these functions as well. So like scream and unlike scream. And here for the here instead of like button here. We do the component like button and we pass it a scream ID of scream ID because we've disrupted it from the screen right here. And here we need to import it for like button from Same level like button. And here in like button inside the component, we need to paste those functions. And here, this approach, the user likes everything. And here we check if the like, scream equals this dot props dot scream ID, because we don't have a scream, we have a scream ID. And actually, we need that in the URL, we have that in the prop types already. This is like button with a lowercase L. Here, we need to say this dot props, dot scream ID. And here the same thing. And here we need to get authenticated. So const authenticated from this dot props dot user. And authenticated. And yeah, I think this is for this component, and we save there. And we save here as well. As check if we have any errors. We don't. Let's check our app, see if the button is working properly. And it is working the same if we refresh to make sure that Yep, it's working the same way. If we log out, or click on the like button, or it doesn't redirect, us check the console. Or this is not working. Everything looks okay. Let me check again. Oh, it's actually working. Oh, I see. Because if we click on the side, that doesn't work, because there's just as big as the icon itself. So what we can do is we can, we can surround the whole button with the link. So let's put this outside, let's put the whole button inside of the link. Yeah, and this way it works. Even if we click on the sides, the whole thing is the link now. Alright, so let's do the same thing inside of here. Let's show these two things here. So now that we have it in its own component, we can just use it like that in the screen dialog. So let's go to scream dialog. Under the body. So right here, we can see like button and pass a scream ID of scream ID. And we have it Yeah, we how we got it from the screen. And under that we need to say we need to have a span. And you will have like count count, like in the scream card. And here we say likes. And we will have as well the we can copy this actually from screen, this comment button and the comments icon and the comments text. So let's save. Actually we need to import it as well. So here let's say import like button from same level like button. Let's save see if we have any errors we do. Chat icon is not defined. Sure we don't need this dialog title. And here let's bring the icon we can copy all this. And here's the Chat Chat icon. And here say just chat. Space save. We have no errors. Cool. All right, let's with get the same button Actually, we have to log in because we're logged out. Alright, so here if I expand cool, we see the buttons here. And if we click it turns into full Oh, but the the like count doesn't update here. Let's check our state data. scream. Do we have any error? The prop uses marked required an auth route, but the values undefined. Okay, this because when we log out, it's okay. We'll fix this later. All right. So the light count is not changing. I think because the the screen is not updating. Yeah, so the scream like count is not updating. We need to update it. So let's go to data reducer. And right here when we like or unlike the screen, we need to do a check. So if State DOT screen singular dot scream, ID, so we need to check when we like a scream, we need to check that scream that's stored in the singular scream object. If they have the same ID, that means we're like the scream that we have open. So we need to update the scream, the singular scream with this data that we get back from the like, or unlike route, which is the scream with the like, count updated. So we do if it equals action, dot payload, dot scream, ID, then we just do State DOT scream equals action dot payload. It should fix it. We open up here, and let's open the state as well to check. We like cool and we get this updated and the like screamers. Look at the difference. Yeah, it no here, yeah, incremented the count. And if we unlike it, decrements. So it updates the data. So this is the current state of our screen dialog, it has only the details of the screen, I want to add a section where we display the comments that are submitted to each screen in this dialog. So let's do that. I'm actually going to create a couple of folders here to organize our components more otherwise, it's going to be less navigatable. So let's create a folder called screen. And another one called layout, and another one called profile. So in the layout, we're going to put the navbar. And then we're going to put the profile and edit details in the profile folder. And the rest of them will go to the screen. Alright, so VS code should fix the the relative imports and change the directories. Actually here and now bar, the post screen would come from we go back one level, and we go into screen slash post screen. And the rest should be fine. In edit details is changing automatically. And it's opening up it open in the mob, because it's changing them right now. And we need to save all files and close this. Let's go to app. And here, we get the navbar we're going to get it from slash components slash layout slash navbar. And in the home as well. here where we get the screen, we get it from slash scream slash scream. And from profile, we get it from slash profile slash profile. Save. Cool, no more errors. Let's go to actually let's get rid of this warning. So let's go to home and remove axios. We don't need it there anymore. Let's save cool, we have no warnings. And our app works the same way it did earlier. All right. So let's add the comments. And let's go to the screen dialog. Here. We're going to import a component that we haven't created yet. Let's do import comments from see this would be in the same directory. So comments like this. And let's go at the bottom. So here when we are actually not loading, and we are rendering stuff, let's go here under this grid right here. So here, let's do comments. And we need to pass it our comments. So let's pass a prop comments with the value comments. And this comment referred to refers to the actually we haven't extracted it yet haven't disrupted it. So let's do that. So it's going to be this comment from inside the screen. Because if you remember from the API, if we go to Redux go to the state. For look at data screen, we have an array of comments. And if we don't have any comments, it will be an empty array. So here we do our comments. And let's save this let's go here in scream Oh, there's a problem cannot resolve comments because we haven't created that yet. In scream let's create comments dot j s. Actually before the comment section I want to add a separator. So here let's do HR class name is classes. And unlike the one we have already, this is going to be the visible separator. separator and I want to move the code the styling for the invisible separator from here to the global theme So let's go to utils theme, unless based at the bottom, because we're going to need it in comments as well. And here, let's do visible separator. And this one is going to have a width of 100%. And as a string, actually, because this is JavaScript, and it's going to have a border button of one pixel solid, let's give it a gray. So I'm going to do RGBA 000. So so far, it's just black, and we give it the opacity of 10%, or 0.1. This is going to be a light gray. So let's give it a margin bottom of 20 pixels. All right, so this is visible, let me make sure I didn't misspell anything I didn't call. Alright, let's go to comments. And here we're going to bring in these three, so react component, fragment with styles and prop types. Here, we're going to need some movie stuff. I know already, we're gonna need the grid. So import grid from material, material UI slash core slash and grid. an import typography from the same material was slash core slash typography. Alright, let's initialize a styles. Actually, we need the global theme. So let's take the theme and return this object. Let's spread the theme for now. And here, let's do our class. Comments, extends, extends, component. And, here, let's do our prop types. So comments dot Prop, prop types, here, we're only going to have the comments that are passed on. So this would be a prop types dot array that is required. And here, let's do export default. With styles, styles, and comments. All right here in the component, we're gonna have the render, render. And here, let's extract the comments to const comments. From the props, this stop props. And, yeah, we need to return something I saved, but doesn't like it. Actually, we need the classes as well. So classes here, let's do return. Here, we're gonna have a grid container, because this is the container. And inside of this, we're going to have, what are we going to have? We're going to look through the comments. So let's do comments. dot map. And for each comment, we're gonna actually, let's do curly braces, because we need to destructure the stuff from inside comments. And if you remember, comments, me check the singular comment, actually, we don't have one as a problem, you need to save her. Anyway, I just want to show you in the state that the comment the comments will have a four four keys. So body, I just want to remind you probably know this body created art and use the image and the user handle. So we get these from comment. So equals comment. And here we do return. So inside we are inside the grid, the container grid, so let's do a fragment. And since this is a we're looping through something, because I'm going to learn in react, we need to give it a key and let's use the created art as a key because it almost never will be not unique. Okay, so here, let's say grid. And this will be an item. Let's give it a width of 12. And inside of here, we're gonna actually nest another grid. So let's say grid container. Because inside of each comment, we're gonna have a left grid item there where there's a picture, the image and on the right, there's the details of the comment. So here this is, here we have the picture. So grid item, as equals, we're gonna have again a width of two inside of it, we're gonna have the image with the source user image. The alternative, let's say comment, we're gonna have, we're gonna give it a class because otherwise, we need to start it otherwise is going to be massive. So let's give this classes dot comment image. On after this, we're going to have a grid item. With SM nine, we don't actually have to specify this because material UI can automatically give it the width nine. But it just looks more readable in my opinion. So there's let's give this a class name of classes. or comment, data, and style, this div lighter. And inside of this div, we're first thing is going to have we're gonna have the, the handle of the user as a link. So typography variant. Let's give it a head of five similar to the one in the scream card. So component, B link, do we import linkwithin Let's import link import link. From react router DOM. Here the component is linked the two will be so backticks slash users slash dollar sign curly braces user user handle. All right, we're gonna give it a color of primary. And here, let's close this. Now actually, here we close it. And inside of the typography, we're gonna have the handles. So let's say art or without an art, actually, let's just put the user handle on here are actually in close this done on what this curly brace I added here for? Hey, we need to show the one the one The comment was submitted. So typography, the variant of body two with a color of text secondary. And inside of here, we're going to format the date Actually, let's import ajs. For digests from DHS, and inside this expression, we're gonna say d, j, s and pass it the created art dot format. And here, let's format to have this in front of me H, colon. Space a call corner, quadruple capital M, d, d, and quadruple y. Alright, so under here we're going to have a separator, so HR with the class name, classes dot invisible is Bo, separator. Oops, here, we're gonna have the body. So let's say typography. But the very end variant of body one. And inside of here, we'll put body and yeah, I think this is it actually has a ruler between them. So let's do here, let's say HR. Class Name of classes dot visible separator. Actually visible not invisible. Alright, let's save. Let's save everything. Let's see what this looks like. So we open up here. Oh, yeah, I forgot to style the image. So let's go here. So in the styles, that's the most common image. Here let's give it a max width of 100 or 100%. Near let's give it a height of 100. An object fit in case the ratios are actually one by one of cover. And let's give it a border radius of 50%. So it's rounded 50 percent. And here we need to style this div as well. Because I want to give it some margin between an image. So it's a comment, data. margin, left, margin, chin left, have a say 20 pixels 20. At save. Look at our depth. So here, cool. If we look at here, we push the rule, actually, we need to not put the ruler after the last comment. So what we can do we need to access the index. So yeah, the map gives us actually access to a second parameter of index, and gives us where in which index we are. So here, let's take this ruler. And let's put a condition here, let's say. So you always want the ruler unless we're in the last index. So let's say index does not equal if index does not equal the last index. So comments, dot length, minus one. So if it doesn't equal the last index, then give us the ruler, so render the rule otherwise, don't render it. So on the last one, it doesn't render it. So yeah, now it doesn't run the ruler under the last comment. Cool. All right, so we got our comments. So now that we're showing comments, let's actually show a comment input or comment form right here that allows us to submit comments as go to scream dialog. And I'm going to create a component for this. Actually, it's not going to be here, it's going to be under the separator, sort of a comment form. And we're gonna pass it the scream ID, because we need this one we're sending one, we're sending a request to that endpoint. By the way, I'm not just creating a component just for the sake of it, it's better to divide your application into smaller components. Because if I were to put the code here on all the functionality and bring the functions from the Redux actions, it's going to bloat this one component. So it's good to separate your components. Plus, it helps when debugging, the problem happens, you will know exactly where it came from. So let's import this. So let's go up here. So import comment form, from same directory comment form. Alright, let's create this in the scream directory. Let's say comment, form dot j, s. And here before we write anything, let's actually create the action, the Redux action. Let's go to Redux actions. Let's actually create a type for this first. So here, let's say export. const. Submit. Comment. Which equals, actually, it's not a string here. What am I doing? Here is submit. fuckin type comment. Alright. I submit comment. Yeah, didn't misspell anything. Here in data actions. Let's bring it in. Submit, comment. Let's go under the unlike here, let's say, submit a comment. Here. Let's do export const. Submit comment. equals, and due to the nature of the endpoint, we need the scream ID. So let's take the scream ID. And let's take the common data. We need dispatch. So let's return dispatch. And then do the following. So here, I'm going to say axios dot post. And the endpoint is slash scream, slash the scream ID. So put a variable here scream, Id slash comment. And here we pass the comment, data returns a promise. So then Russ, here with dispatch, the type that we just created. So type, submit, comment, and the payload, which the payload which when we submit a comment, we get that comment back. So let's do the payload is rest or data. We'll show you in a second what we're going to do with the payload. Here we dispatch clear errors. Since we have the function clear errors here, which by the way, this is called a an action creator when you create a function that just dispatches an action. So let's dispatch this action creator and we call it Like this. And actually, let's look where we have clear errors and replace it with. Let's Let's search for clear errors. Yeah. So where else actually we have somewhere else where we have, I think, yeah, here, we can just dispatch clear. Oops, clear errors, the function. Cool. All right. So let's go back to our Submit. With dispatch this. Are these are curly braces Not, not square, like this. And here, we see a catch. And we can actually get validation errors for the comment, because if it's empty, we get an error for that. So we need to dispatch set error. So type, set errors, and the payload will be the error dot response dot data. Alright, let's save this. Let's go to the data reducer and handle this. Submit comment is not exported, or because we didn't save her. So here let's do or I didn't save, maybe you saved? I don't know. Submit comment? And I think it's important. Yep. And here, let's say, what do we do? We need to Okay, let me do return first. Sometimes it's hard to talk and type at the same time. All right, let's spread the state. And what we need to do is that, we get this comment back. And since we have opened this screams dialogue, so this is in this singular scream object, we need to add this comment that we get back to the comment array in this in the screen. So if we look here, just to reiterate, so here, if we open up this, let's say the screen, let's go to our dev tools, we go to our state. So inside data screen, we have this array of comments, what we need to do, we need to get that comment and put it at the top. So if we were to put a comment here, it will be at the top here, because it's the newest one. And here so what we need to do is we spread the state and we say, scream, which and then we spread our existing screen. So status screen. And here we say comments. And inside of comments. We say action dot payload, which is the comment that we just submitted. And then we spread the rest of the comments. So spread State DOT scream dot comments. All right, let's save. Now let's go to our comment form. Hey, we need a couple of things. Let's get the these three. A safe first ice tub, remove this export here, and then paste here. Here, we're going to need some movie stuff as well. So movie stuff, let's get, we're going to need the button, the submit button of the form. So from material UI slash core slash button. Let's copy this two more times, we're going to need the grid because we're already remember we're already integrated because of the screen dialog. And here we're going to need the text field. Alright, let's do a styles const styles equals theme. And then returns we're going to need the textfield styling. So to spread the theme. I don't think we have any styling for this component. So let's leave it like that. Here we have a state. Since we have a form, we'll have the body of the comment as empty initially. And here let's do actually we need to bring in Redux. So or like Connect Redux stuff, say import can connect. Now guys, you don't have to do these comments. But if you expand your functionality more and you bring in more stuff, it's cool to comment on your on your code or on your import. It makes it easier to navigate. So we get Connect as per usual from react Redux. And we need this action that we just create soldiers to import. Submit comment. From go back one level go back another level Redux slash actions slash data actions. Alright, so here Yeah, we got prop types who can do prop types. But before that, let's let's cut this and let's say export default, connect map state to props. Since we have one action, we can just But her submit comment. And the second one will be with styles, styles. And we pass our component. So here let's do const. Map state to props equals state and returns the following. And here we need to access the both the UI and case we get errors. So UI is state.ui. And we need, we need authenticated from user. Because we don't want to show this form for not authenticated. So let's say authenticated from State DOT user dot authenticated. Alright, let's do the prop types. So comment on dot prop types. We have our function. So submit comment is prop types dot bank that is required. We have our props from the state which is which our UI prop. Prop. Okay, let me try again. prototypes that object that is required. And we can just copy this. Here we see what do we have? We have the classes from, from with styles, and we have the scream ID that we got passed down. This is a string and we have the authenticated, then dedicated. And this is a Boolean, so disable. I think this is it for our props. Yeah. Okay. Let's go to the render, let's say const. Let's get our classes and authenticated from this dot props. And here we say let's say return. Comment, form markup. And here, let's say const. comment, comment, form markup equals, and we do a ternary. operator. So if authenticated, if we are authenticated, we return something else we actually return No, because we don't want to see this if we're not authenticated. So here let's, what do we return we return a grid item because we're already in a container, because of house in screen dialog right here. Where are we? Yeah, we're here. So we're already in a container yet. So we just put a grid item s equals 12. Here, let's give it an inline style. And let's give it a text align. Center. I want the button to align in the middle. Here, let's do a form on submit equals this dot handle, submit. And he will put up whoops, we'll put our text field text field, we're going to have a name. It's going to be body. Whatever we'll we'll have a type of text. We have let's put a label, of course that says comment. On scream. Spread a place hole actually has not put a placeholder. It's kind of self explanatory. So let's put an error of errors dot whoops, Oh, actually, this reminds me that we didn't put errors. So errors comment, this is what we get back from our endpoint. We have an validation error with the comment. So if it if we have a comment, or a comment, we set this to true, else we set it to false. And let's put errors in the state errors. And let's actually get errors from the state. So const errors equals this dot State DOT errors. So here we have a helper text in case we get an error, and this will be arrows.rs comment, sick of saying errors, twisting my tongue too much value equals this dot State DOT body. An on change is this dot handle change. And let's give it forward. Because otherwise it's just gonna take off Let's give it actually the our class. So class name, the global styling, so class classes, classes, that text field. I think this is it. Yeah, let's close this tag. And let's have a button of type Submit. variant contained, because that's the style we've been going with color primary and the class name, the global class name classes dot button to give it the margin. Let's close this. And this will say Submit. And I think this is it. Actually, no, let's put a ruler under here. So let's say, hey, char, the class name. Classes dot, visible, separate. Alright, let's close this tag. And no, not like this, like this. And, here, let's create our form. For methods. So let's say on change takes an event. And here we do this dot set state. Oops, we said the state and the name will be event dot target dot name. We only have one input, but this is this works for all forms. So event, we bind it to event dot target dot value. All right, let's create the onsubmit not on change, handle change. I'm doing this handle thing because in the movie document documentation, they do that. So to be less confusing, I just follow the the convention because I'm using that framework. But you don't have to. So handle submit takes the event. And here we do event dot prevent. Default. And here we call our our action this dot props. dot submit comment. comment, comment. And we passed this paper Oh yeah, the scream ID. So this dot props we've passed, we've been passed this already. So scream ID and the second will be an object with a key body, not Cody body. And the value of this will be this dot State DOT body. And we need to get the errors as well. In case there is any so let's say component. component will receive props. Next props. Here we need to check for them if next props.ui to get you why. Yeah, we did. If next props.ui dot errors, then this dot set state errors. Next props.ui.ui dot errors. calls. I think this is it. Yeah, this is let's test this out. Let's save errors is not defined. Oh, to initialize it as an empty object here. Yeah, fragment is defined but never used. Actually, we don't need fragment, because we're returning one element anyway. Cool. Let's check our up. So we open up. There's no form. Oh, we're not logged in? Of course. So use that we're not logged in. Maybe you're logged in. So use that. At email, comm one through six login. I open up this, we get a comment section here. Cool. I write a comment Hello, mate. I send it call it persist and it shows up instantly. But it doesn't clear the form that's handled up. So huh? here when we receive props, or we can check because once we send this, we can check. Once we get props, we can check that we don't have errors. So actually not here. So exclamation mark. Not errors. I mean not next props.ui dot errors. And the same thing we did in the ad scream guys. So our next Next props.ui dot loading, or just not here as well. And what we need to do here, if this is the case, this dot set state body is empty. All right, let's try again. I say hello again, bro. We send this cool and it resets it. If I send empty, we get errors cool. If I submit, actually, oh, we're not clearing the earth. So I know now, I'm going to submit it's going to show me an error instantly. Yep, we need to clear the errors as well. From here. What we need to do is that we need to clear errors once we close this dialog. So we will do this from the scream dialog. So here, actually, we need to import the clear errors first. So here, let's say clear errors. And where are we so here, in handle close, we need to set the state open to false. And we need to call the clear arrows this dot props dot clear. Earth, call it like this. We need to add it to our prop types. Up here, so clear errors is a prop types.funk.is required. Comma, let's save. Let's go here. So if we get an error, and we go again, and oh, the stop prosecutors' not function is or not clear errors. Call it here. Oh, of course forgot to add it to the map actions to props. Clear errors like this save this time it should work. So if there is any error, let's let's double check as well in the state. So tree UI, there's no error right? Now. Let me put them like this. So actually, no, I don't need to type anything. If I have an empty we have an error. And if I close it, it dispatches clear errors and it clears the errors cool. So let's actually create the user page. So when we click right now on a user handle, it just takes us to slash user slash that user handle and there's nothing. So let's actually create this page. Alright, let's go to pages, and let's create here, a user dot j s, lowercase, it doesn't really matter. I've got questions on this, why use components and pages, it's just a convention, you know, there's multiple conventions on how to do things, just pick yours and stick with it. Alright, let's go to app. And actually, let me close the terminal. Let's set up a route here. So here, I'm gonna import it first. So import user. From same level, but pages slash user. Let me put a space between those. And here, let's put a route. So route, exact path equals, and this will be slash users slash colon handle. Handle not handle. Sorry, for the typos, guys. So component equals user. Now, before we create the sound or create the action, so let's go to data actions. And we're going to create export const, I'm going to call it get user data. But don't confuse it with the other get user data from the user actions. And this will take a user handle and it will go through dispatch. And here first would dispatch a loading type. So dispatch type, loading data. And here we say axios dot get backticks slash user singular. That's how we set up our back end route. Don't confuse the two. So dollar sign curly braces use a handle that we have passed to this function. And here we do, then, then result. Guys, if you remember, if you don't remember, I'll remind you so this is the type of data we get from requesting from slash user slash handle. So we get a user object and the screens object. So what we want to do now is we want to set the screens to our state screams. So here we do dispatch. The type will We'll be set screams and we're not going to set the so payload will be action, not not action sorry, rez dot data dot screens. And we're not going to set the user details to this because the user details is always the authenticated user. Here, we say the catch, we don't need to stop loading because set errors that set screams does that. And here let's do catch errors. And here we just dispatch the same type set screams with the payload of No. Alright, so yeah, no, no semicolon, here, we save. Actually, we don't need or here, we could just like keep it like that. Save here. And let's actually create this user component, or page. So RC e tub, let's get rid of this export. And here, we're going to need the prop types. Let's import axios. And I'll show you why we need axios in a second. Let's import scream. Components slash scream, slash scream, Pascoe cased here. Let's import the grid from material UI. And we need, we need to connect. And we need this function that we just created. So get us a data from Redux actions, data actions. Let's set up our prototypes. So let's actually set up the map the map state to props first. So const, map state to props is going to take the state and return the following. So we just need the data. So So data, state that data. And here let's just do connect map state to props. We only need one action. So we can put it in a object like this. So get user data. And we wrap the component in the parentheses and here, let's say user, the prop types equals the function get user data, which is a prop types.funk.is required. And the data which is an object. So prop types.object.is, required. So here, let's, when we load the component, so let's do component did mount. And here when we load the component, we want to fetch the user, this user's details, so let's get the handle from the URL. So we can do that by doing the columns handle, let's put it in a variable. So this dot props dot match, which holds the details about the URL, the path, name, base URL, all this stuff, the parents, which are the parameters, and we have access to only one parameter, which is the handle, because that's how we set up the route if you remember, so we have this one parameter handle, now we get it, we put it in this variable. And we can do this dot props, dot get user data and pass the handle. And we also now need to get the user details. So let's do axio. So I want to send another request to see got axios slash users slash user rather singular, the same request that we send from our action. So here we pass the handle, oops handle. Get then rather. And then here, actually, we need the profile and the state. So let's do state equals. Here we have a profile property. Survey no for now. And here when we get the result we do this dot set state. We said the profile to res dot data The user and we forget an error, we just console log it. Now I know we can as well create another, another entry in our data in the state and put this data in there. But this is going to be a static profile, it's not nothing's going to change about it. So we don't need to store it in our global state. So we can just fetch it and have it here inside the component. So here in the render, skirt, the screams, and the loading from the data. So we destructure these from this dot props dot data. And here where we return stuff, we're going to have something similar to the homepage. So can we actually copy it from the homepage? Yeah. Let's copy this. Let's go back to user space. This here, we already brought in grid right here. And here, we say, screams. markup. And here instead of profile, I'm going to put a thing called static profile component called static profile, which we haven't created. But we will in a moment on let's pass it a profile, this dot State DOT profile. And here, let's create the screen mock up. So const, screen mock screams mock up equals. And of course, let's check for loading. If we are loading then show a paragraph saying loading data. Else. Here we do. What do we do? Actually, we do another check here. So let's do else if screams, because there could we could go to a user's page, and they could have no screams, maybe they haven't posted then yet. So if screams equals No, then we set we set the content to be a paragraph that says, No screams from this user. Now you can style this more. It's up to you. I'm just gonna leave it like this for now. If we do have any screams, accused, excuse me. We do screams dot map. And then for each scream, we're going to return a scream with the key scream dot scream ID similar to the homepage. And we passed the scream. scream. We close the tag. So I think we're done here. Yeah, let's create the static profile. Let's import it from so right here, say import static profile from go back on level components slash profile slash static profile. Let's create this here. Static profile address. Here let's import react and fragment from react. And maybe let's copy some stuff from here. Or maybe from here prop types. I wanted to get with styles, sexually typed out styles from material UI slash courses slash styles slash with styles. We're going to need a j s. From data they j s. And here let's do import link from material UI. Slash link. Here we need paper. trail uY slash course slash paper. Copy this but it's never too late control the typography, typography. And let's get some icons. Here we say the movie Still, we need the calendar today. So similar to profile so we can get those three icons from here. So calendar location and the link icon. So these three spaced them here. We're going to use styles similar as well to the user profile style. So let's go copy these. Let's go back to static profile, let's paste. And here, I'm going to remove the button because we're not going to have edit buttons, because this is not our profile. This is static profile. So we removed that button. So here we remove as well, the buttons, and the so the buttons from here and we removed this SVG button thing from here. Let's save. And here this, this component is going to be a functional component. So let's say static profile. Equals takes a props. And let's export it. So export default with styles, styles. And what is this static profile? Let's do our prop types. We have profile which have been passed down. So this will be prop types.object.is. required. And we have classes from with classes with styles rather, prop types.object.is required. Alright, so here, we need to destructure a couple of things. So let's say const classes. And we have profile. So we need some stuff from there. So profile colon, and we do curly braces. And we get what do we get, get handle created art. Okay, image URL, and the bio, website and location. And this equals this dot props, actually just props because this is a functional component. So here we do return. And here, let's wrap everything in a paper. Actually, I think I could copy everything from profile and edit it. So it's good to profile, copy this whole paper tag. And let's come here, paste it. So we're gonna need, so we're gonna need the image, we don't need the input and the button here. So let's delete this. We're gonna need the link the same way I did I call it mu link. Let's call it more link from link. And we need the link from react router Dom actually. So let's do import link. The structure is structured from react router, Dom. So we need that we need the link, we show the buyer the location, the website. And here we don't have the edited details of the button to log out. So I think this should work. So let's save everything. And let's look if we have any errors. We don't. Cool. let's reload the entire thing. And let's go to a profile. cannot read property No. Handle have no. So the profile we got passed down is no I think profile check on the user. This that stayed that. Oh, of course. Here we actually check if we have a profile because it could be loading or we don't have any profile. So let's cut this and let's do an expression here. Let's say this dot State DOT profile and the equals No. So for equals No Then let's return a paragraph saying loading profile.dot.we do hear colons. So else we show Yeah, we show this we paste what we had there. So let's save. Let's go back cool. And we get the profile of Jane last. And her screams which are just one could go back to home click on Johnny we get his profile and his scream. And this is the normal screen so we can still interact with it the same way we do in the home. So cool. Like we have now the user page and we can go to it and everything works just fine. What I want to do right now is we need before we implement notifications, we need to set up a way where when we type a URL for a screen we straight away Go to the screen because otherwise when we click on a notification, we can't do anything. So what we need to do we need to set up a way in which when we let's say you want to go to user slash Johnny slash scream, slash scream ID of whatever his scream when we click And to hear, we need to go straight away to that screen. One thing I want to fix first, when we are actually logged out, there's a an error, or a warning that says the proper user in auth route is not required. Let's fix that. So let's go to our auth route right here. And here, let's make it not required, because sometimes we won't have a user if we're not logged in. And that's okay, this is still gonna work. So remove is required, let's save and the error should be gone. And I'm going to be checking if we have any other one warnings and fix them. Alright, let's go to App let's set up a route for for what we're trying to do. Let me close the terminal. So here, I'm going to add another route. So route, exact path equals, and this will be slash users slash colon handle, slash scream, slash colon scream, ID. And this will go to the component, the same component user, but with a trick and you will see, let's save here, let's go to user or as user right here. Now here in user, we need to check if we have this parameter in our URL, or in our path. So here in component did mount I go here, actually, I say const. Scream, ID equals this dot props dot match, dot params, dot scream, ID. Now of course, we could maybe just be on the user's page, so we don't have this, which is fine, it's going to be undefined. So here, we do if scream, ID. So if we have it, then this dot set state, let's call it scream, Id Param. and set it to scream ID that we just got. So if we have it, we set it in the state, sexually initialized here, this variable and give it a valid value of null initially. So we can come down here in the in the render right here. Let's extract it. So const. What is that scream? Id Param equals this dot state. So of course, if we don't have it, it's going to be no, which is fine. And right here, we don't actually just run through the screens, we do another check. So if we actually have screens, then here we do another check. And we say, if not scream, Id Param. So if it's not, then yeah, show the screens like this. That's fine. Now, another. So actually, yeah, actually, here, I need to put a question mark, because this is another ternary, we're chaining another ternary operator. So if not scream ID parents then don't do anything else. So if we have the scream ID params. So we're trying to visit a screen, then let's do this. Now what we need to do here, we need to find the screen that has this scream ID and pass it a property of open dialog so that we will know which screen to open once the page loads. So here I'm going to do if scream dot m. Actually, no, I need to do the map first. So let's do screams, screams dot map. And here I say scream. Inside curly braces in here, we do our Chuck's of F scream, dot scream ID does not equal scream, Id Param then it's not this scream that we want to open. So we just return like this. So I can just copy this the same way we return them here. Now here, else return. Now this is when we actually find that one scream that has the script, same scream ideas that one we're trying to open. So here we just pass a pass a prop open dialogue. And if we just pass it like this is just going to pass the property open dialogue with the value of true. Okay, so now let's go to screen. Now this is kind of this is prop drilling, but it's okay, we're drilling only one property, not massive objects and a lot of updates and stuff like this. So how would we go actually here? No, actually, we need to pass it to the screen dialog. So here in the screen dialogue, let's say open dialogue equals this dot props because we passed it down, dot open dialogue. And so if we don't have, it's not, it's gonna pass a, an undefined value. So that's okay. And here let's add it to the prop types. So we say open dialogue is a prop types dot For bullying, and it's not required because most of them will not have this property. And some, sometimes none of them will have it. So let's go to the open dialog and handle this logic. Now, here, we're going to add a component did mount. So let's go here under the state, let's say component. There did mount. And here, what we need to do is we just need to check if we have the open dialog. So which if you do this dot props, if this dot props dot open dialog, then we just call this dot handle open. Let's save all files. And let's check our application. So let's open the Redux state. So let's look for example, this one. This one right here. So now we have this one in our screen. Let's take the idea of it. So this is by Johnny, and we have the idea of it. So did Oh, no, actually, I typed that. Earlier, I got confused for a second. Okay, let's refresh the homepage, just in case. And now if I type slash users slash Johnny, slash, scream, slash that ID, it should take us to that user's page and open the screen, which it does cool. And, and so now what I want to do is I want to do something like Twitter. So here on Twitter, as you see, if I open this scream, I mean, the scream this tweet, if I open this tweet, it's going to change the URL to that slash that user slash status slash the ID of this tweet. And if I close it, it goes back to the original one. And if I open this, and I actually just go to this URL, so I type enter, who go to that user's page and open it. And if I click away, it just goes back to that user's page. So let's actually implement the same behavior for our application. So let's go to Let's close Twitter. Let's go to our app. So here in the handle open, we're gonna have some logic. So this happens after we open the, the screen. So here, let's make some space. Oops, make some space like this. Let's say we're gonna have two variables here. Let's call this one old path. And the old path will be the path that we have currently. So window, dot location, dot path name. And here, I'm gonna get two things const. Use a handle, handle. And the scream ID remember, we've been passed these down from scream, so equals this dot props. And here, we're going to form the path that is supposed to be the path for this scream. So we'll be we'll call it new path. So this should always be the path for this scream that we've just opened. So backticks, slash users slash, and put the user handle and then slash scream, slash, and then put the scream ID. Now here, we can just do window, dot, push, push state. And here, we don't need to pass any data. So you can say no, no. And then for the URL, we just passed the new path. Let's save and let's see, look at our app. So now if I open this, it should change the URL to slash users slash user slash scream slash the ID of this one. Okay, so push date is not a function. Oh, window dot history. dot push date. Sorry about that. So let's refresh. We open this cool, and we get this URL. Nice. Oh, but it's actually not, we wanted to actually change back. So let's add that logic as well. So here, we need to as well reverted the change from handle close. So we need to store them in the state. So you can access them from both functions. So or methods rather. So here when I said the state, we need to set as well values for the old path and the new path, we need to put them here. So old path. Ups path is an empty string and new path. This is well an empty string. So here when we close the dialog, we want to do a window dot history, which does nothing By the way, it just changed. Is the URL at the top. But of course, it benefits the the application so that we will know where to go. And you will know where we are by just checking the URL from different components. So this dot, State DOT old path. So now when we go, when we close it, it should revert back to the old path. So let's save and let's test that. Let's refresh. Let's open this. Cool, it takes us back to the old path. And even from the Users page, if we do this, and we go back, it gives us the old path. So it doesn't just give us slash, it actually saves the path that we had. And then when we close, it takes us back. Okay, there's an edge case for this, which is, when we just take a URL, let me go to another user because slash user slash user is a bit confusing. So when I take this screen, and I just press enter, right now, there is no old URL. So if I click away, it's not going to work because the old URL is the same as the new one. So let's actually handle this edge case. So here, under here, I'm going to say if old path equals new path, then what we need to do is we need to say old path equals slash users, users slash user handle like this. Because when we come from another from another, from completely a different place, and we click away, we should just go back to the Users page, like exactly like on Twitter, and it works right now. So if I click on this, and I just click enter here, and I click away, it will go back to the Users page. Cool. Okay, so let's create the notifications. Now. Let's go to here in navbar. And here, instead of notifications in this button, let's just leave this notifications tag, but it's not going to actually be the icon is going to be a new component that we're going to create. Let's put it in the same folder. So let's say import notifications from same directory notifications. And let's create this file. So notifications, dot j, s, and here, we're going to have some similar imports to screen. So I'm going to take the first six right here. Let's go back to notifications, paste them, the only one we don't need is the width styles. And for this, we're going to use the menu component. So if we go to material UI component demos, and where is it right here menu, we're just going to use the simple menu. So if you if you expand the code, it has something called anchor element, and you can change the anchor and you will anchor around a different one. So for example, if What if it were to anchor around my account, when you click it, my account appears in the middle. But for our case, I'm just gonna let it always anchor at the top, so we just see as a normal drop down. Alright, so here, I'm going to bring in some movie stuff. So let's say movie stuff. And here we'll say first is the menu is the menu, excuse me. Slash material UI, slash core slash menu. And here, I'm just gonna copy this line and paste it five more times. So let's click here Ctrl. D, we need menu item. We need icon button. We need tooltip. Type, hug, typography, and batch, show you what these things do. We need a couple of icons. So here let's say import notifications icon from material, UI slash icon slash notifications. And we can copy this on here, let's say favorite, favorite. And here we'll say chat. Select this control the chat. Here, let's bringing the Redux stuff. Import connect from react Redux. Here, let's import an action that we haven't created yet. Let's call this mark notifications, notification notifications. Read, which is going to be executed once we expand our notifications. So just like on Facebook, or I think even on Twitter, when you expand your notification They're automatically marked red. So from go back to levels Redux slash actions slash user actions. And here let's do our class notifications extends, component. And we will have a state will have an anchor element of no initially, let's export here, export, connect, map state, to props. And here, guys, if you remember, we already have our notifications, we got the state, we go to user, or actually, we're not logged in, let me log in quickly. So okay, so if you look here, we already have a couple of notifications. So we just need to show them. Alright, let's go to our notifications here map state to props. And we only need one action. And we can put it in the subject is Mark notifications read. And we connected to notifications. Here is export default, let's say notifications dot prop types. And we have only two so the function mark, notifications read is a prop types dot func is required. And the notifications is as well a prop, whoops, prop types.object.is required. And here let's do const map state to props will take the state and return the following. And here we need notifications from State DOT user dot notifications. Alright, let's actually create this action first, because that makes more sense. Let's go to user actions. And here at the bottom, I'm gonna say export default. Actually, let me create the type first. So it imports it. Here under the user types, I'm gonna say export const. Mark, notifications, read. I'm just gonna copy this so that I don't make a typo because I always do that. So equals the string. So let's go back to user actions here, let's say the not default, export const, Mark, notifications read. And here it will take. Let's call it data for now. Or let's call them notifications. Actually, they're an array of IDs. So let's say notification IDs. And it's going to take this patch. And here, we just need to send an axios request. So post to slash notifications. And we pass the what is it notifications IDs. And here that then if we get a result, we dispatch a type of Mark notifications rather than an import system. It's important, we don't need actually a payload. So here we say the catch error. We're just console dot log. So Alright, let's go to our user reducer and handle this type or this type. So here, I'm say case mark, notifications read. And make sure if it doesn't import it for you, you import it yourself. And here, what we need to do is when we mark some notifications read if we go to our state here, so let's go to user notifications. If we mark them read, we just need oops, we just need to loop through them and change this red property from false to true. So we have access to them right now, by just doing State DOT notifications. And what we need to do we need to do for each, we loop through them. For each not I'm going to call it for notifications. We will say not dot read, not read equals true. All right. So here we just we need to return the state of course, returns spread the state. Okay, so this is this is fine. For now let's go back to notifications. And here in the render We need to take the notifications from the props const notification notifications equals this dot props dot notifications. Here, we need to do the anchor element equals this dot State DOT anchor element. And notice I'm not using the structure in here because sometimes it makes less sense to use D structuring when you have one thing. Okay, so let's say let notification notification icon. Now, depending on the type of notification, we're going to have a different icon. So if it's a notification on a comment, we're going to have the chat icon. If it's a notification on a like, we're going to have the favorite icon. So here, we need to check if we have any notifications in the first place. So if notifications, and if we have notifications, we need to check that notifications. The length is bigger than bigger than zero. So if this is the case, we need to, what we need to do is we need to have two types of notifications. If it's red, we're going to give it a color of secondary, otherwise, we're going to give it like a normal color. So here we will say, so here we check. If we have any unread notifications, then we need to show a, so we broke our thing. So we need to show a badge on the icon of the notification with the number of the unread notifications. Otherwise, we just show the icon without any badge. So here, we can check by doing notifications dot filter. And here we filter for not where not the red equals false. So this will, by filter filter in like this, this will have a result of only the notifications that have a read of false. I mean, if the array that has some notifications that have a read property of false is has a length of bigger than zero, that means there are certain notifications that are unread. So here if this is the case, so we use it as a condition, and we do a ternary. So if this is the case, that means we have unread notifications. So let's open this. And let's say notifications, notifications icon equals the following. So here we say badge, we're surrounded with badge. That's how badge works. And when we say badge, content equals and here, we need to actually give it a number. So how many notifications are unread, which is this array right here. So actually, I forgot to change change dot length. So actually, this is the number of the notifications that are unread. So this is the content of the of the badge. And here we need to add a color of secondary so it stands out and we can see it. And here let's close this badge and inside the badge, we put the icon so notification icon, which is just the notification icon. And here, so outside of here between these two parentheses, we do a colon so else, we just do notifications. icon equals just the regular notifications icon. Actually, this is a lower case, because it's it's this this thing right here. Actually, it's this. I mean, make sure I have the right variable here. So notifications icon is this one. Cool. Okay, I have a problem with my parenthesis. I think these are extra. Okay, yeah. So this is fine. Now, we need to handle the else case. So else we can we'll we'll do the same here. So notification icon equals notification icon, because we could have notifications and all of them are read. In that case, we do this and we have no notifications. And in that case, as well as this, we just put the icon. Alright, so here we are actually just to return. Inside, we're gonna wrap everything in a div. Or actually, let's bring in a fragment That's better. So avoid the div soup. So let's replace this div with fragment. And here, I'm gonna start of course with the button that triggers all of this. And here to say we're surrounded with a tool tip with a placement, not placeholder place meant of top and this will Have a title and you will say, just notifications. And inside of here, we're going to have an icon button. With an area area owns, oops, area owns you have if anchor element, then we'll just do a simple menu. This is from the documentation. Oops, else is undefined. Here, which I don't know, I honestly don't know what these do, but they're from the documentation. So I'm just going to put them these two properties has pop up, construe, and it's gonna have an onClick. This dot handle open. And inside the icon button, we're gonna put our notifications icon, so notifications icon. All right, so under this tooltip, we're gonna have our menu, some menu menu like this, here will give us an idea of simple menu in case. Actually, we don't need the ID, I didn't even type it correctly. So anchor element will be the anchor element with that we just that we disrupted the structured earlier, the open will be let's change the Boolean on anchor elements. So if we have one is going to be true else it's going to be false. So the unclose will be this dot handle close. And we'll give it an on entered. Now this all entered is triggered once the menu is opened. And this is what we're going to use to actually send a request to our back end and mark these notifications red. And we'll call this on menu opened as close this and inside of here, we're going to have something called notifications markup. And this is of course, it's going to depend on a couple of things. So here, let's create our notifications markup. So I'm gonna say let notifications, markup equals. And here I'm gonna say if notifications. And notifications, oops, notifications, the length is bigger than zero. So here what we need to do, we're going to map through the notifications and show each one. So here we say notifications dot mob, I'm sorry about the typos guys, like it's the end of the day, and I'm kind of like tired to be honest. And this is going to be the last video I'm recording, otherwise, I'm just not going to be that productive. Alright, so inside of this notification, we're gonna have a couple of things because, like, let me just show you depends on the on the notification, we're gonna have a different string that we put inside of the notification. So, for example, if the type is comment, we'll say commented on if the type of like will say liked your excetera. And you'll see what in a second. So say const verb, I'm going to call it equals. Now depending on the notification that type, so I just called it not by the way, in this map, so not dot type, in equals, like, then we will call the verb liked. Else, we have two types. So else is probably it's definitely a comment. So we say commented on. And here, we need to also have the time when this happened. And for this we're going to use the dangers from now. And actually, we need to extend digest so inside the render, let's say they, they j s dot extend, and we pass it the relative time plugin to actually important Yes, pass it the relative time. And inside of here we'll say time equals day j s, and we pass it not dot created art dot from now. Now we need the icon color. Because if it's unread, it's going to be red. If it's red, it's going to be like normal. So here we say If not the red, then it's going to be primary. Else it's going to be secondary. And we also need the icon, the, the icon depends on the on the type of the notification. So here we close, not dot type, equals like. So if it equals like, then open parentheses, and let's say favorite icon. So if it's a like, it's going to be a hot icon, and the color will be icon, color. Color. And the What do we have, we have, let's give it a style, style of margin. Actually, we need two curly braces here margin, right? Of 10. Doing in lifestyle for this one guys, you can, I don't want to add with styles just to have this style. And here, if not, it's going to be a chat icon, because it's going to be a comment notification with a color of icon color. And with the same style, and we close the the icon like this. Actually, before we carry on, let's handle the else so that it doesn't show any like squiggly lines here. So elsewhere notifications, we show and menu item with an onClick. That just closes this. So on click of handle, close. And it's going to say you have no notifications yet. So here, let's carry on. So now after we have all these variables, we can return what we want to return. So let's return the following. And here it's going to be a menu item. With the we have we need the key because we're iterating through an array with the key would be the created art. And we need an onClick. And this will be this dot handle close as well. And inside the menu, we're going to have the icon The first thing, and after that we'll have a typography of component link, because this is going to be a link to the screen and the color of the fault. And the variant of body one, and it's gonna have a to property because it's a link to slash users slash and we put the notification dot recipient like this, slash scream slash notification dot scream, ID, I will close this typography and here it's gonna say not dot sender. So the the, the handle of this person, space verb, so whether liked or commented on. And then we say your scream, spray, and then here we put the time at the same time like this. And this will say like five minutes ago or whatever. So let's go up here and create our functions our handle open and handle close and all that shit outside the render. So here's the handle open equals, it's gonna take an event. I'm just gonna do this dot set state unka element is event dot target, which is always going to be the icon here to say handle close equals doesn't take anything. And it just sets the state on element to Nola gun, so closes the thing the menus. And here let's say on menu opened, this is what sends a request to our back end to to mark the notifications read. And if you remember properly, like the back end, we need to send an array of the notification the IDs of the notifications that we want to mark read. So we can do this by a say LED on red. Let's call it unread notifications, IDs equals IDs equals this dot props dot notifications dot map. And what we're going to need to do here not, we need to map through the notifications that have a not read or false or not, not read. And actually know here we filter will filter them, not map them. So we only have the ones that are not read. Now we chain a map. And what we need to do we map the notification to not.we have a key, a key notification, ID. So this will return us an array of the IDs of the ones that have red false. And what we need to do with this array, we just need to call this dot props dot Mark notifications red, and we just passed this unread notifications ID and that should take care of it. So this should work. Let's look at our console. And we have notifications icon not defined line 53. Or is it because it's notifications icon. Oh, cool, no more Earth. Alright, let's look it up and cool. We get three unread notifications. And if we open our state, let's, let's put this like like this, we open the state, we go here, we look at our user, we go look at our notifications, and they have a read of false. And if we click here, so now there are already because they're all unread. And if we click on this action, or click on difference, we see that it changed in the notification and it changed all the reds, all the red properties from false to true. Cool. And if we click away, there's no more badge anymore. And if we click we see that there are blue because they are red. And if we click on this one, it takes us to this to this scream ID cool. So right now in our application, if we load if we reload or load our up, we'll see quickly these loading texts show instead of the profile and the screens while they are actually loading. So let's change this into something more visually appealing. The technique that I really like is called a loading skeleton YouTube user set. So if I reload YouTube, you'll see these boxes, these placeholder divs, while the videos actually load, and the thumbnails and everything, let's actually implement this in our application. Oh, by the way, one thing that I changed I fixed from last video, the notifications in the prop types in the notifications component is a prop types dot array and not prop data object because there's multiple ones. So make sure you fix that. So let's go to home. And here in the home while we're loading the screams, we don't say loading, we say, scream, skeleton, which we will create in a second. Let's copy that unless go here, say import screen skeleton from go back one level. And we were going to put this in the util so utils slash screen skeleton. And let's copy this whole import or let's go to the user page. And here paste it. And let's go down here. While we load the data, we just put the scream skeleton is that alright, let's create this component. So when you tell I'm going to say scream, scream skeleton.js I here we're going to need react for react and fragment, because we're gonna have multiple ones. So we need to wrap them in a fragment. So here we're going to bring these from react, we're going to need the no image because we want to show this no image while the images are loading, because we don't have the actual user image. And by the way, I'll put this link in the description so you can download it. So I'm just going to download it now download the 640 by 641. And we can actually just grab a drag and drop it into the image folder. I'm going to call this no dash image. And it's dot png. So let's import that. So import, no image from and by the way this you can name anything, it's just an identifier. So it's going to be from going back one level slash images slash no dash image or whatever you named it. dot png. Let's bring prop types. on here it's good to see Mui here we need three things the card is going to be just like the actual card but with no content material, the material UI slash core slash card. Let's copy this and paste it two more times. This will be called media and this will be called content Actually we need with styles as well. So let's import that. Material UI slash courses slash styles slash with styles. Let's create a styles object, which will take the theme. So I'm not sure if we're going to use the theme, but let's just take it anyway. And I'm going to leave it empty for now. And here, let's say, we're going to make it a functional component, because we don't need to manage any state or do any have any methods. So we'll, we'll make this a functional component. So let's say const. Scream skeleton equals is going to take some props. We'll do parentheses, curly braces here. And let's pause that for a second say scream skeletons dot skeleton dot prop types, which is going to have the classes from with styles. So this is going to be prop types, whoops, prop types.object.is required. And here we need to say export default, with styles, styles, and we're gonna pass our screen skeleton. Alright, so here, we need to do our fake chord. So say, let's bring in the styles First, the classes rather. So const classes equals oops, classes with two s's equals this dot props. And here, I'm going to say return fragment, inside the fragment, I'm gonna put the content, I mean, I could put the whole thing here, but it looks cleaner when I put it in a variable. So say const content. And here, we're gonna have our card, it's going to be like an empty card. And inside there is like a blue div here and a gray div here and this image right here. But of course, we need multiple ones. And I want to fill up the screen. So just in case, I'm going to put five which fills up the screen. And of course, if there's three later, they're gonna see that there's only three. But for now, I'm gonna put, I mean for the loading, we're gonna put five of them. So the way we do this, we can say, so content equals, we can do can use array dot from. And here, we can pass some attributes to this array, and I only need the length of five. So this is basically like a for loop. But, but more efficient. So here, we do the map on this array that we just created. And we do item. And we're going to need to actually more than two parentheses here. So item, and I'm only saying item just to access the index, we don't need the item, there is no item actually. And here, let's do parentheses, we just outright return stuff. Sorry, let's do card, I'm going to give this class name of classes card, because we need this to style these depths. And I'm gonna give it the key of index. And this is why we need index. And here we're gonna have card media, which is the non image image with a class name of classes dot cover. And here, we will say we'll give it the image, which is the no image. Oops, I'm gonna close that like this, because there's no content in here, let's say cod content. Let's give this a class name of classes dot call this card content. Let's close this. And here inside the content, we're gonna have these big divs. So so far, what we have is we have this card with this image, but there's nothing here. So what we want to put, I want to put a blue div here, and then a gray div, and then two full lines and one half a line. So it gives the illusion that there is some content that's being rendered right now, but actually, it's just a fake skeleton. Alright, so here, I'm gonna, the first diff, these are just divs. And we're going to style them. So say, div class name. I'm going to give this a classes dot handle, because this is the placeholder for the handle. I'm just going to copy these paste. What is it four more times to four more times. So this is going to be the date, because that's what's under the handle. And these two I didn't get to do Ctrl D, and I'm going to call this full line is that the two four lines and this is going to be the half oops, half line like this. So let's actually style this. So up here in the styles, I'm going to use Flexbox. To make sure that they, they are arranged properly, one on top of the other. So for the card, yeah, so we gave this card, we're going to style this card itself. Let's give it a display of flex a margin bottom, just like the actual cord of 20. a position to it to give a position No, I don't think so. Alright, so let's do a comma. And here we have our chord content. For this, I'm going to give it a width of 100%. Because by default, it takes the minimum width. Absolutely, this needs to be a string. kind of confusing jumping from CSS, back to JavaScript back to CSS. Alright, so flex direction, and give this a direction of columns. So they stack up on top of the of each other. And I'm going to give it a padding just like the actual card of 25. And here, let's style the image to cover we're going to give it a minimum width, otherwise is going to be not visible at all. So of 200 and an object fit of 200 of 200 cover, even though I know that this image is actually a square image. But in case the dimensions changed, I don't want it to be like stretched or like kind of shrank. Here, we're going to style the handle. So handle. So guys, these are divs. So by default, they take zero width, so we need to give them a width. I'm going to give this a hard coded width of 60 pixels, and the height of 20 pixels. And the back background. Let's just say background colors, the background. And here I'm going to give it the color from our theme the primary color. And if we go to our theme right here, where is the Utila theme, we need to access this property. So we need to access the palette dot primary dot main. So back to our skeleton here, let's say theme dot what is that pilot dot primary dot main. And here we need our theme to access that. So let's spread the theme. And then do comma. So this will have the blue like a link word. And here let's give it a margin bottom. Otherwise, they're gonna stick to each other. Let's give it seven. Alright, let's let's save let's see what this handle looks like. Alright, there's a problem here cannot read property. Props of undefined. Oh, this is not a class based component. So we don't use that this keyword. Let's go back. Let me reload. Alright, so we see. Okay, we can actually use Redux to pause our animation at that state. So we can just go here, go back one step, actually here. Alright, so we can pause at the loading of the data and we can see our skeleton. Alright, so this looks cool. Not bad, we need to add the other ones. Because if we don't style them, they're here but they're gonna take zero space. So let's actually style the full What is it now the date. So the date I want to give this a should we give it I think we should give it a like smaller height, because it's kind of a smaller font. So let's give it maybe 14. And should we give it I think we'll give it more width. Let's do 100 for the background color I want to give Hey gray, so we can say okay, I'm gonna use RGBA. So I'm just gonna give it a black with the with opacity. So not point, I think not point three with do. And let's carry on and actually style the rest so we have the full line. Now this will take a height of 15 because this is a bigger font size. And for the width, we're going to give it a percentage value. So I'm going to give it 90%. I could give it 100 by four to give it 100 is going to come away here and that Not our actual actual code looks like. Let's give it a margin bottom margin bottom of 10 pixels. Actually, I forgot to give this a margin bottom margin bottom, give us seven pixels or 10 pixels 10 pixels. Now we have the half line, which is going to have the same height, it's going to have a width of actually 50% is going to have a margin bottom, the same one. All right, let's save. She's got to our app. Let's go back to the loading state. And interesting, we don't see the other depths. To get this depth, oh, we didn't give it a color, of course, as take this background color here to control or like Altair, and then paste it. Let's make this a bit darker. So here we'll do Ctrl D and give it naught point four. Let's save. Alright, let's look at our app. Let's go to Redux go back to the loading. Actually, I want it to be much darker than this. So let's give it nonpoint. Thanks, six, we'll do save. Let's go back to our loading. Okay, so this is a health line as well. So make a mistake. So full line. Oh, yeah, this needs to be half line, the way CSS works is that it takes the latest one, so ignore this. Yeah. So this is how offline not for loan. So it's save us go back. All right. I saw for a second by looked cool. All right. So this looks perfect, I think. Okay, you see the difference? Now it goes from here to here. Maybe the user, the user dev needs to be a bit shorter. So here, the handle. So here, let's give it a height of 18. Okay, yep, this is more. It makes more sense this more appropriate. All right, cool. So if we were to just play, press play, and if we're to reload, this looks so much better. And even if there is some sort of, like delay, it doesn't, it doesn't feel like there's any like delay from from the server to the client. Alright, let's make the profile skeleton as well. So let's go. Let's go here and utils and create another file called profile, skeleton, dot j, s. And let's go What do we need that you need in the user. So here when we are loading, they need to say, profile skeleton. And let's import that. So here from the same directory, select this control DSA profile skeleton. Let's go to the home as well on here. So profile profile, fuckin type skeleton. Right here, when we are loading the profile, actually, this is going to be inside the profile. So oops. So cut that and let's go to profile here in profile profile. Here, let's import it. Actually, we go back one more level. And right, right here, so in the loading, say, profile skeleton. And actually, a lot of the styles that are going to be used in the profile skeleton are going to be the same as the styles in the profile. So we can just cut all these these styles and put them in the global theme. So cut that and spread the theme like this so we can still access them. Let's go through the theme. And at the bottom here, let's put a comma and paste all that stuff. And actually, you could do the same thing for static profile. So here just select the entire thing and just remove it and spread the theme instead. And let's save and make sure that we didn't break anything. Our theme is not defined. And theme.js Oh, okay. has to be this okay. So this Yeah, we can't refer to it like that we can just copy the value. So this let's go here. Yeah, okay, because our screen skeleton doesn't have anything yet it doesn't export anything yet. Let's start creating. With the snippets, I'm going to do RFC E, tab. And change the syntax to const profile skeleton to the arrow syntax. And we're going to need prop types we're going to need with styles, slash core router, style slash with styles. We're gonna need the no image port no IMG from we go back to levels, or one level images slash node dash image dot png. Here we need the paper just like the actual profile from paper from material UI paper. And we're going to need the same icons. So let's go to the profile. And let's get let's get the all the icons here. And the only ones we don't need all the return and the Edit because we don't have a logout and edit button. Here let's see movie. Oops. No, we let's declare styles const styles equals theme and returns nothing for now let's do prop types. So profile, skeleton dot prop types, equals I'm gonna have a classes prop types.object.as required. Yeah, that's it just classes. Let's get these classes. Props like this without the disk keyword. And here let's do paper with a class name from the global classes, classes dot paper. And here kind of similar to the profile so so there's actually like really similar to the profile except the buttons. Class Name classes dot profile. And inside of here, we're going to have the image wrapper, which is just actually a normal String class. So dot image wrapper. And here we'll have image with the source of no IMG given alt profile, oops profile, the class name of profile dash image. Here we could put a horizontal ruler. And here I say dot profile details, we have these from the proof from the global styles. Here, let's put a div with a class name of classes dot handle. HR to make some space is that a another div with a class name of this is going to be of two full lines because this is going to be a fake bio. So as to classes dot full line. Just going to copy this one more time. Copy and paste it and put the HR and here we're gonna put the location icon so location on the color of primary. And we can put like a placeholder word or we can put a place to hold a div. I can like we can even put some word in there. So I'll put location like this. And here let's put HR and here we'll put the link. So the Websites link. And you can omit these, by the way, guys, because maybe a user wouldn't have these at all, I'm just going to put them, you know, just for reference. So if you want to not use them, if you're just like skip, like, or like not use these. So I'll put the link icon, I'm just gonna put a dummy website, so HTTPS, colon slash slash website, Comm. But another HR, and here we put the join date. So calendar today, they call of primary that's going to be joined, they date. So let's style these placeholders. So here, we spread the theme, so we can use it here for the handle, it's gonna have a couple of things gonna have a height of 20. By the way, don't forget that the rest of this stuff is already styled from the global theme. So just style the image or the handle rather, it's gonna have a background ground color of the, the blue, so we can use the same palette, so themed palette, that what is a primary, not main, we're going to have a width of 60. Here, we'll have some margin to actually adjust margin. So margin. So the first one is the top, let's do a string. So I give it seven on the top, so seven pixels. And on the right and left, I want to give it auto. So right it's going to be auto, auto bottom, actually that the top is going to take seven not that. So the top zero, I mean, the bottom is going to take seven. So here I'll say, seven pixels. And then here for the left, I'm going to put auto. So actually, that set the handle next thing is we style the the full line, so let's do full line. And here we're gonna have a height similar to the God stuff 15, and the background color. And we're gonna have the same grace. So RGBA 000, and here is 0.6. Let's give it a width of 100%. And let's give a margin. So here we need. So I think you're on the top, although on the on the right. And on the bottom. Actually, could we give just the bottom, let's try just the bottom, I think there's the bottom would work. So I'm just going to give 10 on the bottom. And yeah, let's copy all of this space to call this half line. It's gonna have the same height, the same color, but the width will be 50%. And the margin bottom will be the same. Let's save all of this. And let's look at our AP classes dot paper is a problem cannot read paper of undefined. Oh, it's because here we need to say with styles, because we don't have classes otherwise. So past styles. And we passed the skeleton. Alright, let's go back to our app. Go back on the profile loading. Cool. So get the two full lines for the bio and these icons and the location. So press play. We just reload our app. Go it looks fine. These, by the way the snap in is because we only have four screens. So we get to this scroll bar, which pushes the content and then once the content loads, it goes away. So once we have more screens, this snap in is not going to happen. Alright, so we're done with the skeletons. Yeah, actually, guys, we're done with the app. So now that our application is done, we can actually bundle it up and deploy it to Firebase. First of all, we could build it out and test it first. Sometimes there's production errors that you don't foresee. So what we're going to do in the app in the terminal, we're going to run NPM run build, which is a script that comes already already in create react up applications. Now is going to build it to this build folder. Alright, now that it's built, so everything is here the static files And everything, we could see the into that. And I have this package this tool called live server. And you could just run live server in that directory. And we get a problem. And the problem is the server responded with status 404. Okay, so what is trying to do is trying to get to the is trying to get Ryan to this I forgot to fix this is trying to get our resources from localhost from the same origin. And the problem is like, our proxy only works in development. So we can, we need to actually set up a way to tell axios to always send requests this instead of the local, not local host or the machines IP. So here in app j, s, so I'm just going to say, Here axios dot default, dot base URL equals and we just give it this URL. And this should fix that problem. So let's again, build it. pm run, build. Alright, let's run it again. Cool, it works, we get our data, no errors, and we get the users can even like go to the Users page. And the Users page doesn't work. Oh, okay, we get a cross origin error. So this is a course error. Actually, this is my bad this is from the server. Let me fix that right now, actually, so in the functions, and if you've done only the React part, then don't worry, I'll fix this. And it will, it should work for you. If you've done your own functions, then go to index JS in your functions directory. And here Actually, let's go into functions, we need to install something called course. So npm install course, was just add some headers that tell our application that you can give these resources to any anyone that requests them. So now that it's installed here, we can say const. Course equals require course like this. And we just need to tell our Express app to use this middleware. So here we say course use, I would just I mean up us, and we pass course and we call it here like a function. So let's save. Let me deploy this function. So Firebase deploy. Okay, now that it's done installing, or deploying, rather, we could reload our app. Since seems to get the user's details. Okay, it was just some. Sometimes when you deploy on Firebase, it takes some time for the code to work. And it works a bit weird at the beginning. All right, so everything works, fine. I can log in. So let's try to log in here, just to make sure that everything works. And I do login and everything is fine. Cool. Let's actually deployed to Firebase. Now you go to Firebase, go to your app. And if you don't have an app, you can create a new one, you can go back to part two of this series. And there we set up Firebase tools and everything related to that, go to hosting. And I've already enabled it because I've already tested the host, you know, I don't want to have like some problems on the video, even though I already had a couple. So you could just click Enable, and it will work. And let's go to our app here. Let's stop the development server or like the live server, go to the root directory. And here we're going to initialize Firebase up. So let's do five days in net, just like we did for our Cloud Functions. Here. Let's say yes, I want to proceed. And here we want to use the hosting. So space on hosting and press Enter. And select this up. Do you want to use No Actually, we don't want to use the public. We want to use the build directory. That's where our build files are. So we say build, configure single page up. Yes, we say this. already exists. overwrite. Yes, overwrite it. Cool. So we've already built our app, we could just run Firebase deploy. And if you want to make a change, you just make your change and you run NPM run build, you build your your app, and you just run Firebase deploy a new will deploy it. Alright, so it's done deploying this is the URL head control and I click it. Whoops. Alright, there we go. So we get our application is deployed. Let's try to log in. All right, the login works. Everything works. I can post the screen Hello from deployed up Submit it, and it works. Cool. All right, so this is deployed. So we're done with this project completely. Guys, please any feedback anything you want to know anything any praise, likes subscribes, please feel free to and let me know in the comments if what you want me to do like a video on any framework. I've got a bunch of video ideas right now. So feel free to like, you know, contribute. So thank you for watching and I will see you soon. Bye
Info
Channel: freeCodeCamp.org
Views: 930,561
Rating: undefined out of 5
Keywords: react, redux, firebase, express, materialui, javascript, cloud functions, authentication, crud, web development, single page application, tutorial, course, full stack, react tutorial, redux tutorial, express tutorial, social media app, create a social media website, deploy to firebase, firebase tutorial, javascript tutorial, react course
Id: m_u6P5k0vP0
Channel Id: undefined
Length: 725min 30sec (43530 seconds)
Published: Mon Jun 24 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.