Hello everyone! In today's video, we'll be building a full-stack social media app from scratch with React, Firebase, and Chakra UI. Our app will have all of the most robust features of a full-stack application like form validation and client-side routing. We will also implement authentication with Firebase Auth to log users in and we will also use Cloud Firestore as our database back-end and also cloud storage in Firebase for users to upload their profile pictures. You can create posts and you can like posts and write comments on posts in our application. You can also delete comments and you can delete posts as well. And you can also view all of the user profiles in our app. Finally, we'll build functionality to upload profile pictures to cloud storage. And once we're done, we can also choose to log out from our application. So this is how our back-end Firebase console looks like. We're gonna have authentication which is managed by Firebase and we have all of our user profiles here. And then we're gonna have our Firestore database to store three collections, one for the comments, one for the posts, and one for all of the user profiles. And then we're gonna have storage here to store the avatar files for every one of our users. And by the end of this video, I'm gonna show you how you can deploy your fully functioning web application to an online hosting service. And we're gonna deploy our app to Hostinger. Hostinger has very kindly offered to sponsor this video. And I've been using Hostinger for quite a while now and I have to say that I'm really impressed with Hostinger's H-Panel. So H-Panel is basically Hostinger's hosting control panel and that's what you're seeing here. And in case you haven't realized, my demo app that I was showing you earlier is hosted completely in Hostinger's H-Panel. Hostinger's premium web hosting package also comes with a free domain name which I'm using right here to deploy my demo app. And have you noticed that sweet small little lock there in the top corner that indicates we have an HTTPS connection to my demo site? That's because Hostinger has automatically installed an SSL certificate in my demo site for me and I never had to touch this. It just does it automatically and it expires at... that's right, never. That means I never have to worry about this and it just does it automatically. Just yesterday, I tried out their customer support and I was able to talk to an actual human and not just some auto reply chatbot just within minutes. So if you ever need web hosting solutions with free daily or weekly backups, go to hostingger.com slash ravenjs and you can get 10% off all deals. And if you're fast enough, Hostinger is having this special Black Friday deal that you can get on top of the 10% off if you use my Hostinger link. All you have to do is just click claim deal, just add that to current. I recommend getting the 48 months plan because you save the most with this plan. Just go all the way down here and fill in all your payment details here and remember to use the coupon code ravenjs and just hit apply. And that way you can get 10% off on top of any special deals that Hostinger is currently having. So to start building our application, I'm going to make a new folder called social media app. And I'm going to take that and drag it to terminal so I can run yarn, create, react that and then dot. So dot basically just means create a react application in this current directory. Let me hit enter and let that run for a bit here. With our app now created, I can just drag the folder to VS Code to open it in VS Code. And let's get rid of some of the files in the source directory here. So I always go and get rid of all of these files here that I don't need and just delete that. And then you have to go to our app, get rid of that and all of this. I'll just return an empty string for now. And I like to always make this in one line to export default function app. And then in index we're going to get rid of basically all of this except for app. And so that and report web vials. And now before I start the server with yarn start, I always go and make a .env.local file and set browser equals to none. The reason for that is because I have to do yarn start every time I make a big change like every time I install a new package. And I have to keep restarting the server and just keeps opening a new browser tab in my browser and I want that. So I just set browser equals to none and I can just do yarn start and it won't start a new browser tab every time I restart the server. Chakra UI is going to be the main component library that I'm going to be using for this project just because Chakra UI, I find it to be the easiest to set up and the least configuration required for the best looking components. So I'm just going to copy this line here to install Chakra from Chakra's getting started website. And just go to terminal and paste that line in. And then at the same time we have to go and add the Chakra provider to our root application in our React app. So I'm just going to import, see how they do, import Chakra provider. So let's import Chakra provider from usually it has auto complete to help me import this in VS code but because Chakra UI is installing right now. So I have to just do this manually for now. And then let's just Chakra provider here and just wrap the app component inside of Chakra provider. It's having issues resolving the package. So I'm just going to fix that. All right. And that's done installing. So I'm just going to say right off the bat, you don't have to be very well versed in Chakra UI to be able to follow along with this tutorial. But if at any point in time you run into anything that you don't understand about Chakra UI that I'm doing, you can just go to Chakra docs and just like let's say you don't understand how the button component works. Just search up button and just see how the implementation is like in the website documentation. And hopefully that'll give you a better idea of what I'm doing in the tutorial. And with Chakra UI installed, there's just two more things we have to set up. And that is React router. So if you look at our demo app here, you can see that we have different routes. I can go to all users. It will change to slash users. If I go to home, it's dashboard. And to do that, we have to handle all of the routes with this library called react router. So I'm just going to do yarn add react dash router dash dom. Just let that install with react router dom now installed. And I just realized that I have put this Chakra provider wrapper in the wrong file. I actually intended to do that in app.js. So I'm just going to move that over here real quick. I'm just going to add Chakra provider here. Just get rid of that from index.js. It actually doesn't matter, but just best practice and I just prefer to have in my app.js file and just leave the index.js file as clean as it can be. Now let's go ahead and make our very first route using react router. So first we are going to have to make our router component here. And that is going to be in our app.js file. I'm going to just do router provider and then it's a self closing tag and import that from react router dom. And then we have to pass in a prop called router. And this is our router configuration object that we're going to have to give it to react router in order to process our routes. So I'm not going to make this router config object within app.js. Instead I'm going to make a new folder in our source folder called lib and let's make this route.js file. You know what maybe routes.js. And then here we're just going to make a router object and just pass it in here. So let's go ahead and do const router and let's export this equals to an object. And then here let's just make that import statement. So import router. So here what you can do is import that from dot slash library slash routes. But I don't like the dot slash conventions here and by the time we get more and more nested routes we're going to be seeing stuff like dot dot slash dot slash dot slash and a bunch of that. So that's a problem with relative imports and that's why I'm going to just install absolute imports right from the get go. So I'm just going to go to this medium article here to install absolute imports. Then we can just do like import router from then lib slash routes without the dot dot slash. So just copy that and go to our jet.js config file here and just paste this in here. No, it's JS config dot JSON. And now we save that and can just do import router from lib slash routes. So this is very useful down the down the road when we start to have more nested routes and I just prefer to have it done from the start so we don't have to refactor our import statements later on. And if you're using TypeScript there's a different config here.  So now we have that. We can go to our routes.js here and make our router. So I'm just going to do create browser router here and import that from react router DOM and here is going to be our, it's going to be a list of all of the different routes and each route is going to be an object inside of this list. So let's make our very first route. I'm going to make a constant to store the URL. So export const let's call this root equals to just a slash. So that's our root and then here in this object this is our very first object in this list. I'm going to make the path call root and then we're going to have an element So this is ideally going to be a react element. We can just, I'm just going to use a string here that says public root just to show you what this does. And this has, this usually this will be like a react component like root or something because I don't have any components yet. I'm just going to use a string. So let's do that. And then I can just zr on start. And so we can start the server. Let's go over to our browser. Let's just refresh this. I'm going to just inspect and open up the console. Those words are really small. I'm just going to zoom in and let's refresh this. See if we see public route. There we go. While we're at it, let's just go and add a few more routes here to our browser router. So I'm just going to add two more and let's go in the export const. The reason I'm exporting these constants is because when we're referring to paths within our components, within our app. We don't want to hard code the path in each of the individual components and instead we'll usually want to reference the constants here that were exported from this routes.js file so that whenever we make a change to the routes, we don't have to go through each of the components and just look for all of the different references. We just update this in one place in the constants file and just work throughout the entire program. So I'm going to make a login path here slash login as well as a register. So register. Register and then here we can have our path be login and also register. Now instead of just doing public route, I'm going to make a component folder components and let's make a sub folder here called auth. And in this auth folder, I'm going to make two components login.js as well as register.js. And let's just make empty functions here first. So react functionally component. Just do that. Let's save then here instead of just using the string as the element, we can actually use the login component that we just made. So you see that now I can just import login from components slash auth slash login. I don't have to do like dot slash components or whatever. So that's like the why you would use absolute imports in a react. And here in register, I'm just register. There we go. And then now if we go to our browser and we do slash login, it says login and if we do register, it says register. Great. Now that's done, that's actually going to write some code for our login form in our login.js file. So I'm just going to close the rest of the files that we don't need here. So in login here, I'm just going to get rid of that import react because we don't need that in the newer react versions. I'm just going to return. So there's this running joke in the web development community. The hardest thing you're ever going to do is center div as a web developer. But that's not true now with Chakra UI because Chakra has this component called center that we can just use to center our components. I'm going to give the center 100% width and I'm also going to give it 100% view height. And then in this center component, I'm going to make a box. So if you don't know what any of these components are, you can just as always just go to the Chakra UI documentation and just look at the component specifications in the documentation. So like if I go to box here, you can see what you can do with the box. You can change the background color of the box and you can add the padding. You can set the color. So we're just going to go back to our code here and let's continue with our box. I'm going to give our box a margin X of one. I'm going to give it a max width of MD. So this will kind of act as our container. It will not let the width go more than the medium break point. So in Chakra UI, there are these things called break points and there's like XS and then there's small and then there's medium large and then extra large. And then there's the second level of extra large. All right. I'm also going to give this box a padding of nine units and I'm going to give the border one pixel in thickness.  And then here inside of this box, I'm going to add a heading here from Chakra UI. Just say call it log in. So we are going to give our heading a margin bottom of four. This is for the input fields below this heading. We want to add some space between the heading and the input fields below. I'm going to set the size of this heading to be large. And then let's do text align. Let's center this heading as well. So align equals to center. Let's see how this looks like in the browser. So if I go to slash log in, we should see our box. You can see the border is of one pixel and it's slightly rounded. And then we have our heading and then our padding, our margin of four below the heading. And next for the input fields, we can always go and like make an input like that and then just like an input like that. And then it'll show up like that. But I'm not going to do that and I'm instead going to wrap all of this in a form here. So the reason for doing that is because if we're using forms, we can just use the enter. Just fill up these fields here and just hit enter and it's going to log in. Without the form component, you'll have to explicitly click on the login button and trigger the on click listener in React to be able to submit the form. So hitting enter won't submit the form. And that's why we have to use our form element here instead of just using react control inputs. And also using, I'm going to use a library called react hooked form which will help us write form validation. So like if I get rid of this back part and just hit enter now, you can see that we have like form validation tells you that email address is not valid. And just having react hook form simplifies that process. But before we install and implement react hook form, let's just go and build out the basic UI components first in the form. I'm just going to leave the on submit call here empty. I'm just going to like on submit equals to like a blank function, a blank arrow function here. So it does nothing right now. The form doesn't submit. So the way you make forms in Chakra UI is you can have form control components like form control and this component we have like form label. And then we have our inputs here. All right. So I have to get up to install and just just prompts me the right thing to fill up in the code. So I have a type of email here and the placeholder is email. And then here in the form of the form control, I'm going to just going to demonstrate how to use form validation. So there's a prop in Chakra UI form control component called is invalid. And I'm just going to hard code this to true just to show you how it looks like if there is there is indeed an error. I'm going to give I'm going to add some spacing. I'm just going to add to two units of padding in the wide direction which means top and bottom the form label. You can just make this email. And here we have our placeholder. You can have like email like user at email.com. And then here I'm going to just add a form. You know what? Before I do anything, let me just show you how this looks like in the browser. So it looks like this for now. And you can see that the email input is highlighted in red. And that's because I have my is invalid equals to true here. And that's why it's red. If I have this false, it's not going to be red. So let's leave this true. And I'm also going to get like I'm going to put form error message here from Chakra UI. And we can say this is an error message. Let's see how that looks like. So that's how you make errors in our Chakra UI form. Come back here and just take this and do the same thing. But for password, so let's change this to password and type. Let's change this to password. And then we can change this to password 123. Let's see how this looks like. And here password. All right. So that's nice. And lastly, let's go ahead and work on our submit button. So I'm going to go below the form control for the password field and add a button from Chakra UI. And this button is going to say log in. And let's let's style this a bit. Let's give it some spacing on the top. Let's give it a margin top of four. This type has to be submit and the color scheme. I'm just going to give it like teal. Maybe I'll just change the entire project's color scheme to teal instead of the purple in our example. You can give this size of medium and then the width. So I'm just going to see how that looks like. So you can see it's like on the left. So we can give it a width of full and it'll just take up the entire space. And the Chakra UI's button has a few useful props like is loading. And we can just set this to true just to see what it looks like. And then you can see it's spinning and loading. And we can also give it a loading text logging in. And that looks good. If we add three dots, it'll look not without the three dots. All right. What we can do next is add that register link. Don't have an account register instead link here down at the bottom. So if I go back to log in and you can see that line of text don't have an account registering instead. So let's add that. So how we're going to do it is we're going to use this component from React Router called link. So the link from React Router DOM and we can just go and add that under our form component link and just register. So link register. And then that's a clickable link and we can add the prop for two. And we can always just do two slash register. But as I mentioned previously, we don't want to hard code the routes in our components because sometimes you want to change the routes a bit. And we don't want to have to go through every single one of the nested files to look for the links. So instead, I'm just going to import this register constant to register. And here it's going to import from the library. So you can see the benefits of using absolute imports very clearly now. Instead of using dot dot slash slash library routes, we can just do library slash routes because the absolute location would be in the source directory. So we don't have to do any dot slashes and relative imports. So now I'm going to link to register.  It's going to bring us to the slash register page. Well, one thing you're going to notice is that we can't style this very well. Like we could always style it with the React style prop using style, just like text or font weight, make it bold. And we can style it like that. But we already have check UI and our UI components. So instead of just using the style props from React, I'm going to import the link component from check UI. And here you can see we have our link component that has some of the styles that we can use. And of course we can pass in more styles of our own into the check UI component like color. Because if you do color here on the link component that's provided to us by React water, you can't do just color equals to blue. It doesn't work, see? So now let's go and import the link component from check UI. And now it's going to clash because we have two different link imports. So let's just change the link from React water to router link. So link as router link. And here this link component is going to be the check UI link component. And now if I add color equals to teal, you can see that actually works. I can change the color weight to 800 and then make it darker. And then we can also go and do font weight to medium. Then we can add our underline. So let's do text decor equals to underline. And they'll make it underlined. And then so now the thing I'm going to do next is make it so that there's a highlight. So we can see it highlights the background when I have hover. So I'm going to do hover. This is a check UI thing. I can change the background to not purple teal. So hover, it gets highlighted. All right, that's nice. I'm also going to just add some margin on the top. Margin top equals to six. So it doesn't stick to the button. You know what? No, let's add the margin to a parent component called text, which we're going to import from check UI. Because I want to be able to type other things that aren't the link here. For instance, I want to write like, don't have an account space. And then here we can have font size of extra large. Align this to be center and give it a margin top here in the text instead. So here we have our don't have an account prompt register instead. Let's write instead here instead. There we go. And there's it's going to be stuck together. So we have to add some space like that. There we go. But now one thing you're going to notice is that clicking this register link doesn't do anything anymore. Because it's just we have to use the router link component from React router DOM to be able to actually make a functional link. So the chakras link is just for styles. And then for functionality, we're going to make this link render as a router link. And then Chakra is going to style this link. And then it's going to implement the functionality of the Chakra, the React router link. So save that. If I click on register instead, you can see it brings us to register page and it works. But before we make our login form work with functionality, I'm first going to want to make our dashboard component in our dashboard route. Because if we don't have our dashboard, the login form doesn't know where to go next. We're just going to log in and we're not going to be able to tell if we're logged in or not. So I'm going to go to our components and make another dashboard folder here and make an index.js and make a React functional component. And then here, let's name that dashboard. And here, let's just call it dashboard. And then here, we're going to add that to our routes. We have to make export const dashboard equals to... We can always just do slash dashboard. But the thing is, I only want the dashboard to be accessible by users who are already authorized and logged in. I don't want just anyone to be able to go to dashboard because I don't want users that are not signed in to be able to go to dashboard. So I'm just going to make it protected and add slash protected to it. So basically how this works is if you go to our... Let's go to our demo page here. So let's say I have protected slash dashboard and if we go there, it's going to kick me back to the login page. See, because I'm not logged in. If I go to protected slash profile slash whatever the profile is that hit enter, it's going to kick us back. It's always going to bring us back to the login page because we're not logged in. But if we are logged in, for instance, in this tab, I can hit enter. It's not going to kick us back to the login page because although we're in the protected path, we're logged in. So we just have to make the logic to check for the protected routes. For that, let's make a protected route. And then the way we implement that is we go to ReactRouter here to make another path. We call this protected. The layout element here is going to be our layout element which we're going to have to make in our components folder. And then we can pass in children to this path of protected. This is going to be another list of objects. These objects in here are going to be the protected slash whatever path. So protected slash dashboard or protected slash posts, users, profiles, whatever. Let's just put this as a string for now. So this is a string. And then children, let's just leave that empty. And then I'm going to go to my app here. We can go and look at protected. And then you can see this is a string. I can do slash protected slash whatever. It's not going to exist because we don't have that route. If I do protect dashboard, we're not going to have that route. So let's go and make that here. We can make our path. Let's make it dashboard. And then the element is going to be our dashboard element. And then if I go to protected slash dashboard, you can see that it doesn't give us an error anymore. But you're going to notice that it's not going to say dashboard. Instead, it still says this is a string. And that's because in order to make a layout component, we need to go and like we need to use this outlet component from the react router library to be able to render children elements. Because right now, this is essentially it's just a react component that's just a string that just returns a string. It doesn't have a way to return the children components. So let us actually go to our components folder and make that layout component. So layout and let's do index.js react functional component. Hello, react functional component. There we go. Layout. And then here, if we do index, it's just going to keep returning index regardless of what the children is and what the sub path of it is. So instead of just doing that, I'm going to use the outlet component from react router DOM. So basically the outlet component is how react router knows where to insert the children. If I say that this is the child and just do outlet here. And then I go to routes instead of the string and I do layout. Right. And then dashboard is here. Right. So if I go back, you can see this is the child. This is the child dashboard. And then I can make more children routes. I can make like a test, test, like just test. All right. And then test one. So if I go to slash test, you can see this is the child test one. And then if I make another child and let's do test two. And then the element test two, then you can go to test two. And you can see the child is test two. All right. Now that we're familiar with that concept, we can come and get rid of all of those children components there. And then what we're going to do is go to the layout component and actually implement the functionality here instead of just writing, this is the child. So what we have to do is we have to go to our path name and check if the path name starts with slash protected. And if it does, then we want to check if the user object exists, meaning if the user is logged in or not. And if they are just rendered whatever child component there is in the outlet component. But if the user isn't logged in, then we have to redirect them back to the login page. So how are we going to do this? So let's go first check if the path name starts with protected. And how we're going to do that is by using a hook that's provided to us by the React Router DOM library called useLocation. So useLocation, that's a hook and it returns a location to us. And this location object has a path name property in that object. So instead of doing this, so what we can do is we could just take that path name and just destructure inside of the first line itself. And that way we can save on one line. But if you don't want to do that, you can just do like location. And you could always just console.log the location object to see whatever it's in that object. So let's refresh this. And now we're out here, so let's just go to dashboard. And you can see that we have an object here and it has a hash, a key, a path name, search and state. So what we're interested in is the path name property. So let's just go and do path, path name. And then now if I refresh this, you can see the path name is a string that's giving us the path slash protected slash dashboard. All right, now that we have the path name, we can use effect here from react. And then let's just get rid of the console.log. And here it's going to take in an arrow function. And then here, let's just say if path name changes, then we want to run all of the code here and use effect. So let's do if path name dot starts with. So starts with is a JavaScript method that we can run on strings. And if it starts with protected, let's just console.log protected route for now. And let's go and refresh this. So we are in protected route. If I go to slash login, for example, then it won't say protected route. But if I do slash protected slash dashboard, then it says protected route. And instead of just logging this to the console, let's go the extra mile and let's just redirect the user to the login page whether if they're logged in or not for now. So here we're going to use another hook that we can import from react router DOM and it's called navigate. So I'm going to do console navigate equals to use navigate. And using this navigate function here, we can navigate the user to our whatever the desired route is. So here it's going to be login. And we have to import that from our library, our constants. So library slash routes and login is a constant and we're just going to navigate the user back there. So let's see if this works. So I can already see that it works because I'm back in the login page despite me leaving this on the protected dashboard route. So let's go back to dashboard. You can see it just kicks us back to the login page. Let's try it. Let's try it again. All right, protected slash dashboard. Okay, look, it just doesn't let us go to the dashboard just kicks us back to the login. So everything's working as intended. To check if the user is actually logged in or not, we have to get our hands dirty now with some actual Firebase stuff. So to do that, we have to go and create our Firebase project in console.firebase.google.com. So we're going to go and add a new project and we can call this whatever we want to just make it social media app. We can hit continue. We don't need Google Analytics. Let's just give it some time to buffer. And now that it's done, we can hit continue. And it's going to bring us to our dashboard. And the first thing we want to do is make a web application by clicking on the web. And then we can call this React app. And then we don't need Firebase hosting. We can just register the app. And it's going to make our very first web app connection. And then we have to add the Firebase SDK to our React application here. It's going to tell us to install Firebase, which I am going to do. Let's go to our console and just stop the server, yarn, add Firebase. So hit enter. And then while that's installing, I'm just going to come here and copy all of the code here. And we're going to go to our library folder and add a new file called Firebase and just paste everything here. So ideally, you don't want to have all of your API keys and your project ID and whatever in your source code.  And equals to your app ID. But for simplicity's sake, I'm not going to do that in this video. If you want to do that, you can just do what I showed you in the env file. And then just do like app ID and just process dot env dot react underscore app underscore whatever the name of your environment variable is. And now that my Firebase package is done installing, I can restart the server. And then here I'm just going to get rid of all of the comments. And then we're going to import the SDKs for the Firebase products that we want to use in this project. There are three products that we're going to use. One is the Firestore database we're going to use for our posts and our users, our user profile information and our comments and everything like that. And I'm going to use authentication for user authentication and storage for the files, the avatar files that users are going to upload to our app. So we can import and get Firestore like that. And we also have to import get auth from Firebase slash auth and then import get storage. And then once we have all of those SDKs imported, we can go and make our handles here. So I'm going to export this because we might have to use all of our handles for our Firestore auth and storage SDKs. So I'm going to do that three times. This is just going to be a constant DB and then instead of initialize app here, I'm going to do get Firestore app. That's right. And then here let's do auth and then here just get auth app. We also need one more. I'm just going to clone that and we need one more for the storage bucket. So let's do storage and then equals to get storage app. And now I'm going to go to our Firebase console back here and let's go to build and then authentication. Here we have to initialize. We have to get started here and go and activate our email and password signing provider. So let's go and click on this and you have to just enable that just toggle that and then just hit save. And now we have that enabled. And I'm going to go back to our layout component here. So in the layout component, we want the path name to start with protected and also and if the user object is not defined, then we want to navigate the user back to login. So the user object we have to get from our own hook. Ideally what we want to do is we want to make a hook here and the hook is going to be like use auth. It doesn't exist yet. I'm just going to write this here so you get the idea of what we want to achieve here. So this use auth hook is going to be our custom react hook that we're going to write. That's going to return us a user object and also an is loading prop that tells us if the user is being fetched because fetching the user object from Firebase is an asynchronous task, which means that there's going to be a loading state. And while this is loading, we want to return early. If it's loading, we just want to return loading and we don't want to render the children component. So we just want to return loading and we just want to cut everything off. And this use effect hook is complaining to me and giving me some warnings and I think that's because I'm returning too early here. I'm returning before the use effect hook has time to declare. So I'm just going to move the return statements down and save that. And obviously not going to run yet because we don't have this use auth hook that we have to make. So let's go ahead and make that. I'm going to go to my source folder and make a hooks folder and let's just do auth. So we're going to have hooks for posts, hooks for users, hooks for comments and likes and stuff. And I'm just going to make a file called auth and we're going to have all of our auth related hooks. And this is just export those hooks. So export function use auth and return. Let's just return an empty user and then it's loading is false for now. And I'm going to just import use auth from hooks. While I'm back here, I'm also just going to add the user object in the use effects list here just to watch for the changes in the user object as well to run this code. And then I'm going to go and see how this looks like in the browser. So if I go and refresh this and I go to protected slash dashboard, it's going to kick us back to login, right? But if I go to the hook here and I change user to be true, let's just make it a true object. Let's go back to protected dashboard. And you see it doesn't kick us back immediately back to the login screen because now user is defined and the program thinks we're logged in. That's why it's not kicking us back and surrendering the child component of dashboard with the layout component. Now instead of just hard coding the user value to be true here, I actually want to make this so that it fetches the user object from Firebase. So how do we do that? I'm going to use this library called react firebase hooks, which has just gives us a bunch of pre-built Firebase hooks that we can just use to get the user objects and to use stuff like Firebase storage and Firestore, Cloud Firestore. So let's go and install that library, stop the server, yarn at react dash firebase dash hooks. And a while that's adding, I'm going to come here and this is the react firebase hooks documentation. We can see that tells us to import the use auth state hook, which we can just import. So let's import use auth state. And then here, I'm going to just copy this line and put it in our own hook here. And instead of the user, I'm just going to change the name. You can change name here because it's not an object. If it were to be like that, then we wouldn't be able to change. We would have to do something like rename user, the user property to auth the user because it's just a list. So the only thing that differentiates the objects is the positioning, the order. You can just name this auth user. And then loading is loading and then error is just error. All right, and then here are options. If you look at the documentation, you can see options here. Options is optional. We don't need to specify for the options. So I'm just going to get rid of that. The auth is going to be our auth instance, which is basically the Firebase auth handle that we exported from the Firebase file earlier. You see this auth object. So it's just import auth from library slash Firebase and pass it into the use auth state hook. Then here, let's just return the user to be auth user for now. And then is loading can just be is loading. Basically, it's just is loading is is loading. But because of ES6 syntax conventions, we can just do is loading and then it will work the same way. I'm also going to just pass error in to the return object. And now if I save this, go to our React app, we go to our dashboard and we first have to start our server. So you aren't start and just wait for that to compile. And now it's running. It can go back to our website and let's try going to protect the dashboard again. And it's going to kick us out again. So that's great. And now that is actually going to write the functionality for the login form. So ideally, let's go to the form. Let's just close everything. And in the components in our auth and login form here. So we are yet again going to write another one of our custom hooks to handle the function, the login functionality. So it's going to look something like this. We're going to destructure a login function as well as an is loading indicator from our use login hook that we're going to make. And we're going to import that use login from hooks slash auth. And then I'm going to go to hooks slash auth and let's export our function called use login. So it's going to return. It's going to have a loading stage for one because we have to return. Remember, we have to return. We're expecting a login function as well as an is loading state. So let's go and make is loading set loading. And we're going to use state for that false. And then we have to import use date. Can I just use auto import here? Yes, I can. And here I'm going to make a function. It's going to be asynchronous function login. And so here, let's take in some props. We're going to take in an email, a password. And then the third one is just going to be redirect to redirect to is going to be a prop that we can specify where to redirect the user to after the user is successfully logged in. And I'm just going to give it a default value of dashboard. So if we don't provide a redirect to property, it's still going to work. It's not going to crash. Just going to do the default behavior, which is just to redirect to the dashboard. And then here, let's just start by setting a loading state to true. And at the end, we're going to just set loading to false after we're done with everything. And then Firebase has this function called await. It's called sign in with email and password. We can import. So sign in with email and password. It takes in auth, the auth handle, which we import from library slash Firebase. And then the email, which is from here in the password. And you have to import that. So I guess we have to import sign in with email and password from Firebase slash auth. This is an API call, which means we have to await that. And then that's sometimes we're going to run into errors because what if the user tried signing in with a password that's wrong or a user tried signing in and he doesn't have an account yet. So we have to use try catch to catch all of the errors. So we're going to try that, right? And then we are going to catch an error. And then here, if there's any errors, we're going to notify the user. And if we succeed in our login, we're also going to go and notify the user. So how we're going to do that is by using Chakra UI's toast. So I'm going to go to Chakra UI's documentation here and just to show you the toast component. So the toast component, if I hit show toast, you can see that we have these alerts that we can just open up with Chakra UI. And I'm just going to go back to the code here. To use toasts, we will get a toast handle and use the use toast hook from Chakra UI. And then here, if we succeed in signing in, we're going to toast the user. And the title just says, you are logged in and then the status success. So they'll give us a green toast. We can set it's closable to true. And then we set the position to top. And all of these problems, by the way, you can just look at the documentation in Chakra UI to find. Like the variance and the status, the closing toasts, you can just go and look at the documentation. I'm just going to speed here and just give it a duration of 5,000 milliseconds. So we're going to toast. And then after we're done toasting that, we can navigate our user. So navigate, remember how to navigate users. We have to use navigate. So const navigate equals to use navigate import that from a React router DOM. And then once we toast them that you're logged in, we're going to navigate them to the redirect to property. So by default, that's going to be dashboard. And then if we fail, let's just toast them and tell them that logging in failed. And then the status can be error. They'll give us a red toast. And then we can give it a description of error.message. So that's error, the error object that we're going to catch. It's going to give us a message property and it'll give us a more descriptive description of what happened. Like if the user failed, the password's wrong or the user doesn't exist. And we can give it's closable to be true, position top again, and then duration is to 5,000. And then after all of that, we're going to set log in to false. And then, okay, so that should be pretty much everything that we have to do for our login function. Another thing I'm going to do is I'm going to come here and return false. So let's say return false if login failed. And then if it succeeded, we're going to return true. And then return true if login succeeded. All right, so now we can go to our login component here and implement the functionality for this login hook. So remember earlier when I was talking about React hook form, and now we're actually going to have to install that library and use the React hook form's hooks to implement the functionality for a form and handle the unsubmit functions. So I'm going to stop the server and let's install. So you aren't at React hook form. So we're going to add React hook form. And then in React hook form, there's this hook called use form. We're going to import use form from React hook form. And then use form returns a bunch of things that we can use. And it's going to return a register function, which we're going to register. We're going to use register the individual fields in this form. So usually how you would deal with forms in React is you would make a value and then you set it to some state variable and then you do on change equals to whatever set text and stuff. But using React hook form, we don't have to manually type out all of the set state and whatever other props that we have to manually pass into the inputs. And we can just use the spread operator and just do register. And this register is coming from the use form hook and register takes in the name of the field which we use to identify the specific input field. In this case, it's email. So we can just do email. And then we can also do the same for passwords. So I'm going to just use the spread operator again on register, which will return an object. And then we can just do password in here. And we can save that. Another argument that we can pass into our register functions is the validation functions. So in here, I'm just going to do email and validate. And that's going to be a function that we're going to write in our utils folder, which I'm going to create in a second. And password is going to have the password validate function as well. So I'm going to go and go to our source folder and make a folder called util, utils. And then let's do forum-validate.js.  So here you can see we have email validate and we have password validate. And this is basically just a regular expression, just regex. And you can very easily find regex patterns from the internet or just Google it. Or you can just use like GitHub co-pilots, regex suggestions if you have GitHub co-pilot, which makes it very useful. And then basically you can just pass this validation, validating function to the React co-form register function argument. We have to import that, of course. So let's import and I have to save this. And then here we can import, import the email validate as well as password validate. And if you want to customize these validation functions, you can just go and take a look at the validating functions yourself and you can change, you can customize the message, you can change this message to something else and you can add more patterns or just modify the regex patterns if you know how to do regex in here. So with that, we can also get handle submit from the use from hook and they'll just handle our submit first. So handle submit because usually when you submit a form in React, you'll have to do something like e.prevent default to prevent the default behavior from form submissions, which is to refresh the page, but you don't have to worry about all of those details when you're using use form hook from React hook form. So handle submit will take in a function, which you can just call it handle sign in and you have to make this function up here. So a sync function handle log in. Actually you can just call it handle log in to make things easier first. So handle log in, it's going to be a function and usually what it looks like is this handle submit function is going to take in an arrow function and it's going to have like a data object that you can then pass into your handle log in function which you can receive the data object from here, but because there's a shorter way of writing it you can just omit that part and it'll still work the same, but pretty much that's just for your understanding. We're going to receive this data object from the handle submit function from the use form hook, which is from React hook form. So in the data object we're going to have all of the properties that we specified. So we're going to have our email and we're going to have our password. So before we do anything we can just console log the data object for your understanding. So let's go and it's going to it can't resolve React hook form. Let's refresh this and we're not going to be able to submit this form because the button is perpetually loading. So let's go and fix that and let's just comment that out. So test and then test here enter it's going to tell us please include it. So to do that then you can see here when I hit enter it's going to give us this in the console that says email. This is an object that has the email property and also the password. So basically that's how the React hook form works. So we can use this data object and we can call the await login function which we're getting from our use login hook. So remember that in our login hook we're expecting an email and password and redirect to is optional. So let us go and give this login an object that has an email and emails basically just data.email and then password just data.password and then we can just do redirect to equals to dashboard. It's not going to do anything extra because we already have the default behavior here but this is just for us to simplify our future development so when we want to come in and add this redirect to functionality in the future it will be reminded that we can just do it straight from here this handle login function and we don't have to go and modify the login hook. So we can do that and then we can use reset. Basically reset is something we can get from the use form as well. We can reset it's just a function. We can call the reset function here which will reset the entire form basically it will clear the form's input fields. So if I come here type that and we'll hit login. You can see it resets and the login toast appears and that's all working and that's really cool. The thing you're going to notice down the line is if we fill this up and there's an error it's going to reset and we don't really want that to happen we only want the form to reset if it succeeded in logging in. So remember that in our login hook we return false if the login failed and we return true if the login succeeded so we can just const succeeded equals to await login and then if succeeded then we reset the form if not we don't so let's try this again and we hit login we hit login the dot is we use the dot two times right it's add whatever okay hit enter and you can see there's an error and it doesn't reset the form. The next thing I'm going to fix is this perpetual error state that the form is in right now and that's because I have the is invalid here hard coded to be true in the form so how are we going to get the errors from the use form hook? So basically after the new React hook form update we have this new variable called form state that we can destructure to get the errors variable here from use form and I can just console out log the errors variable to show you what it is so if I come here you can see right now the errors is an empty object because we haven't submitted the form yet but if I give it an invalid email address so this is an invalid email address because I don't have to dot right and if I give a password that's too sharp and click login you can see that it prints out an object that has the property of email and password so email and email says email address is not valid and password must at least be six characters long so the email object is basically referring to the email field or passwords referring to the password field and how do we differentiate and set the names of these properties and that's why we had our register our register function and the argument name there email so we've changed this to like email and I refresh that and you can see that it's going to have to refresh this page and let's give it an invalid email an invalid password you can see that the address is to email so basically the how you know the names of the properties of the objects is by looking at the register functions that you have in your form I'm going to change this back to email and I realize that the email address is not valid message has spelled has the word address spelled wrong so I'm going to go to our form validate function here and fix that and change this to email address with two D's and we can refresh this and see that the email address is not valid it's fixed and if we fix this you can see that now the email property is gone from the error object and we just have the password that's left and fix the password by giving it more than six characters you can now see that the object is now empty because we don't have any errors left so let's go and change our error messages here so instead of giving this just error we'll do errors.email and then here this is errors.password and then we'll do the same for is invalid so I'm going to take this and put it here I'm going to take this and put it here alright so if I go back to my browser I should be able to refresh this and see that there's no errors right now if I give it a wrong email and wrong password I hit login it's going to give me this error which is the reason it's giving me this error is because if we look at the email object here you can see that this message is under the property with the name of the message and basically what I'm doing is I'm doing errors.password and errors.password is an entire object in and of itself so this entire thing this is the error.password object so I don't want to be putting that into my children this position here as a react object because that's not a react object that's an actual JavaScript object so I can make it a string by referencing the dot message property and let's go and do the same for email and that should fix it so if I refresh this so the message property is undefined and that's because the message property isn't defined from the start it's only defined if we submit the form and there are errors so we can fix that by saying if errors.email if that exists then we're going to render out the message if not it's just going to not render anything so errors.password and then let's refresh this and fingers crossed it's going to work this time so let's do that let's hit login and it works alright so our login form should be fully functional at this point if I do test user at dream.com and give it a render password and try to login it's going to load for a bit and it should give me an error here that says error.auth.usr not found and when you realize that the login button keeps loading and that's we have to fix that because we wouldn't be able to try again if that happens so it's going to be in the hooks here and it's going to be set loading to fall it's going to be okay so we have to clone this before the return statement because this return statement cuts this function off from running that line which is set loading false okay so let's refresh and test user at dream.com some password and there we go but I want to see the form in action before I actually complete the functionality for the register form so I can go over to my dashboard here and just manually create a user so let's add a user test user at dream.com and give it a password that's really strong so password one two three just add the user here and let's just try to login it's going to tell us wrong password which is a better error in the sense that this error now exists we just don't know the password so I'm going to put the password in here and click login and we're going to what is this error okay it's going to tell us that we're logged in which is nice and it's going to bring us to the dashboard so the login form is now actually fully functional with that done now let's go and build our functionality to log out the user because we're logged in and there's no way to log out at the moment so to do that I'm going to build a nav bar at the top of the screen here and add it to our layout component so go to components and let's make a navbar folder I'm going to collapse everything so that everything is neat again just collapse and just reopen our navbar just add index.js and it's going to be a react functional component name we can call that navbar right so at this point I'm just going to start taking some snippets from my code so that we can speed up the development process and I'm going to just paste in some container some flex containers in here and just we have to import the flex containers from Chakra and then I'm going to show you how this looks like in the browser but I have to first go to my layout component and instead of just saying this is the child and we're going to add our navbar there in our layout component so ideally we want this navbar component to show up in every one of the protected routes pages and that's why we're putting that in the layout component because the layout component is the component that renders in every route that's in the children of the protected route component alright so we see, okay so that's what we see we see our navbar here and you can see it's basically just a small bar here with some tint on the top and dashboard just there because dashboard is from our dashboard component here this dashboard component to show you better what this flex container does I can just change the background to something like purple and can go back to our browser and just refresh you can see that okay let's go back to the dashboard I have to login to the test user I forgot the password oh it's password 123 alright so we're logged in and then that's purple and then if we go back to the code we take this background and we put it here red so that's the red section so the red section is where we're going to be putting our buttons and the purple section is just there for the layout and I am going to take this link component and let's put it in this flex container and of course we have to import the link from Chaco UI and then the router link we have to import that manually so import link react router DOM link as router link and we have to import dashboard as well so let's import that and now we see our home link over there and then I'm going to copy a button component just put it down here as well so under link I'm going to have button and we have to import that from Chaco UI and then we're just going to comment the onclick and is loading so we have our button and our link and we can take out the colors so just like our login function we are going to make a hook for the logout function as well and we're going to go to auth and export function use logout and okay so what we're going to do in here is we're going to have a loading state and we're going to return okay first we're going to return an object that has logout as well as is loading and is loading is just going to be from react state so is loading and set loading is use state false and we need an asynchronous function called logout because it's an API call so to actually call the logout function I'm going to go back to their react firebase react hooks documentation and there's this function called use signout that I can just copy it's a hook that I can just put in here and actually the loading state is going to come from this hook which means we don't even have to implement our own is loading hook I'm just going to change that is loading and we have to import that use signout so where do we get that from it's going to be from let's see here it's going to be from react firebase hook slash auth alright so this it's already up here use auth state and use signout and here we're just going to do await signout go to documentation and for use this use signout the use signout hook you can see that it returns a return is true if this function was successful or false if there was an error so we can just say if await signout if that's true if we succeeded then we're going to toast the user and tell them that they have successfully logged out and we're going to navigate them back to the login screen so we're going to need two hooks for that we just see we're going to need const navigate equals to use navigate that's to redirect the user back to the login screen after we're done with the logout we're also going to need to use toast to toast the user let's just toast first we're going to toast them I prefer to just have it successfully logged out there then we have status to be success we have isclosable true position top duration 5000 getup co-pilot is a life saver by the way and we can navigate them back to the dashboard or more like the login page after they're logged out because the dashboard is just going to send them to the login page anyway and then we can have like an else here like else show error because signout returns false if filled and we should be able to just go to our navbar now and do const logout equals to use logout I think oh did we name we named it use logout alright and it's going to be is loading here we have to import the use logout hook from hooks I don't know why the autocomplete isn't working here hooks slash auth did we export this function yes we did okay and then unclick should be logout is loading is just is loading let's see if that works so I'm going to go back to my app let's hit logout and it works and then we can log it back in at test user at gmail.com there we go logout again just to make sure it works and it does work sweet so now we're finally going to work on the register forum and then we're going to do the actual posts and the users and user profiles and comments and stuff so I'm going to go to my auth hooks file here hooks auth and then under use login I'm going to make a function here a hook called use register and I'm going to write all of the functionality for this use register hook before I go and actually do the UI for the register component which is here right now it's just an empty component let's finish up the functionality first okay so use register let's start with our return value so we know what our target is so our target is going to be to return two items which is the register function and then the is loading function alright so it's loading variable sorry it's loading state variable so let's make the register function first that's going to be asynchronous function so async function register so the register function is going to take in a user name an email password and redirect to again to redirect to the page that basically this is just the page to redirect to after the registration is successful I'm going to give it a default value of dashboard and then let's close this tag here so basically the way we're going to deal with user profiles in this project is by show you my existing sample project here we can see that we have our authentication tab in the console in Firebase console and basically this is managed by Firebase we don't have access to we don't really change the table here because this is basically managed by Firebase and we just tell Firebase to create a user and the user just shows up in this table but we're going to make another table inside of our firestore database and I'm going to make a collection called users and here we're going to store all of the user profile information for our users and I'm going to what I did was I basically just made the ID and here the ID field and document ID the same as the ID in this user's table so if you look at Hostinger you can see it sakes something to for VCN if you go to firestore database you can see that the ID is pretty much it's basically the same and that's how I match the ID, the users from this table and the users in the authentication table and here we can basically store whatever values we want to store about this user, we can store their avatar URL, we can store the date that the user has created the ID of the user and the user's username so basically when we call this register function here we're going to do two things we're going to have to add the user to the fire basis authentication table and we have to also make our own user profile entry in our firestore database so let's go and make our loading state here and so it's loading and settling, we start with false and we're going to set loading to true when we start our register function the next thing we're going to do is we're going to add the user to the databases but before we do that we want to check if the username that the user enter which is from this variable here and we want to check if the username already exists because we don't want two users with the same user names now if we try to put the email like the same email and the email is already registered firebase has built in error handler to tell us that this is an error the email already exists because the username is our own value our own property that we have in our called firestore database it's not in the authentication tab you don't see a username here you just see user ID you see their email but you don't see a username here so we have to manually handle our username our user to prevent duplicate values in our user names so I'm going to call an arbitrary function called as username exists here this is a function that we're going to have to add ourselves later but I'm just going to ignore that and just treat it as a black box for now and just say if const username exists equals to is username exist and we're going to pass in the username here and it's going to be an API call because if username exists has to go and check in the firebase firestore database to see if the username already exists so we have to be careful and remember to add a weight in here and we say if username exists then we're going to toast them that username already exists and tell them that's an error and then we're going to set loading to false and it's very good to get a co-pilot has already written all of that for me so that saves some time but I still have to make the toast handle here and then then we can just do an else here and then we can return actually I don't think we should return false here at all because then set loading false will never run because the return statement cuts this function off before we can reach that point so I'm going to do a try catch block here because the user might be trying to register with a user name register with an email that already exists and firebase will throw as an error so we have to catch the error here so try create user with email and password so this is something we have to import from a firebase as well so up here we import create user with email and password just go all the way back down look for that line and we do that so basically this function expects an auth handle which remember we're importing from the library auth handle object there so we're going to pass that as a first argument and then it's going to take in an email and password so once this is done basically we already have our user created in the firebase authentication table but we have to now go and manually add this user to our user profiles table in firestore so I'm going to do await set doc and now this is actually the first operation that we're going to be doing with firestore so I have to go to our firestore go to build, go to firestore actually I have to change back to my current firebase project and because this is the first time we're using firestore we have to go and create the database for the first time or it's going to fail so I'm going to start in test mode and let's see I'm going to just enable this it's going to take a while to enable I'm going to come back here let's just import set doc so import set doc from firebase slash firestore and then let's come down here so we're going to set the document and then we're going to have to get a document reference here so I don't know why it's not we have to manually import that let's import the document and then we have to also import the database handle because now we're working with the database and not just the authentication featured so here I'm going to just make a document reference the first argument of the document reference is going to be the database handle which is db and now this is going to be the name of the collection that we want to set this document to which is just users and then here I'm just going to put the id of the document and what the id of the document is going to be is just res.user.uid so we're getting the id from the response from the response here the response is just giving us back the user object that has been created by firebase and then it's going to generate an id and it's going to be in the response so we can just do the uid then here we're going to have to pass in the data object here the actual document so the document is going to have an id of the document id which is already here but the reason I'm going to make an id here and just pass in an id here anyway is because the way firestore works is that it doesn't return you the id when you try to get the doc later on and you have to manually parse the id which is why I'm just going to skip through all of the hassle of doing that and just manually passing in the id field here as well usually you don't have to do this you can just get the document's id to know what the id of the document is but I'm just taking a small shortcut here and also that's why I'm using set doc and not using add doc because I want to set the document's id and I want to make that equal to the user's id in the firebase authentication table and I don't want to just generate a different id for me here and I hope that was all understood easily understood and if you have any questions about it you can just ask in the comments I'll do my best to explain in detail so the id will just be the response dot user dot uid and the username will be the username of course but we can do dot to lowercase just to make everyone's username in lowercase and the avatar let's just give it an empty URL for now until the user updates their profile their avatar is just going to be the default avatar and the date basically just the date of creation when this user leaves the platform so we can do date dot now that's going to return a time step and basically the recap of what this entire line does is that we're calling set doc which set doc is typically used to update documents in firestore but if the document doesn't already exist firestore won't throw you an error it'll just automatically create the document and so the first argument is going to be the position of the document basically the document reference where in firestore are we going to put this document at so I'm just specifying it to be I'm just giving it the database handle the name of the collection and the id of the document so yeah and then the second object the second argument is just the document object itself which is the data that I want to put in this document and so after this is done we should now have the user's profile in the firebase authentication table and we also have the user in our own firestore custom user profiles table and then once that's done we can finally toast the user and we can tell them that I'm just going to copy this entire toast and put it in here to save some time and then we're also going to navigate them to the next page and I have to define what navigate is right so const navigate equals to use navigate there and it's going to navigate them to the dashboard by default as default behavior and then and then we're going to catch the error here and we're just going to tell the user what went wrong just basically a toast that says sign up failed and then I'm going to add another block here that says finally and I'm just set loading to false here in the finally in the finally block and just save that okay and so now basically the only thing I have to fix in here is I have to fix the user name exist utility function which I'm going to just make here newTills we can do is user yeah this is your name exist.js and I'm just going to take the code and put it here export default function is your name exist I have to spell function write and this is going to be an asynchronous function because it's a it's a call it's a checked it's a call to the API to check if the username exists or not so I'm going to make a query object here and I have to import the query function from Firebase slash firestore and basically it's we're going to take in the username here and basically we're going to query the collection and we have to pass in the database handle of course and the name of the collection which is users and then we're going to use where the where clause to check where the username of the user is equals to username and I have to import that too so collection and where right so now that we have this query it this hasn't done anything yet it's just a it's just a query specification it hasn't made an API call to the firebase firestore backend yet so I have to now actually make the call to the firebase backend using this query object so I can use the get docs function which I have to import as well so we get docs and we put in queue which is the query object and then we have to await this and it returns a query snapshot that we can get in this variable and then here we can just return query snapshot size grand zero so if the size is grand zero it means that this get docs function found documents that matches this query and that means the username already exists otherwise it's going to return a false which means the username doesn't exist yet so I can save that and we're pretty much done with our use register hook and here we just have to implement the functionality in the UI component in register.js so here in the register form I'm just going to cheat a little and just go and copy and paste my entire login form it's pretty much the same just with an extra field and I'm just going to rename this to register and then here const register is loading equals to use register use register here and so I'm going to have to rename this to something else because it clashes with the register function from the use form hook maybe just sign up that way it doesn't clash and save we're just going to handle register or handle register that works then register or more like sign up and sign up it's going to expect data it's going to expect your username too username is data.username username okay so here I'm going to have to add another form control field for username and type type is just text so we can omit that placeholder is username the name is username errors.username and then errors.username here pretty much shit and we can just change this to register and then we want the loading text to be signing up and then here instead of don't have an account we can change this to already have an account and then log in instead and here we're going to link them to the login page so I can get rid of the register constant and I'm not sure if this is going to work but we can try and open up the console that's pretty much everything we had to do for the registration form we have to change the text from login to register so the heading is here register alright let's just do like test user test user at gmail.com password 123 register the email address is not valid okay so I forgot to change the validation function here so for username instead of email validate we do username validate import that so let's try and refresh this form test user test user at gmail.com password 123 register gives us insufficient permissions I'm going to go over to my fightbase console to see what's happening here it seems like it failed creating that firestore initialization when I was first doing it we have our firestore database here I'm going to try refreshing this page and doing it again so test user test user at gmail.com password 123 again so I'm going to go to my rules and see if we have to read write to be false so this is in production mode which means the security rules it's not allowing us to write to this table if we're not logged in I'm just going to temporarily change this to true and just deploy this in development mode for now because it's not that secure because we're allowing read and write access to the public but that's an issue that we'll deal with later on okay so let's try this register page is working password 123 register and it says email already in use so I feel like that messed up our first attempt messed up the database I'm just going to delete this account here check if there's anything in my firestore database nothing okay so let's try registering again it's going to give us insufficient permissions 123 setting up okay alright so it worked in the end so there was just a weird firebase glitch I think and if I go to my firestore and console and just refresh it I should see a user here in my firebase authentication table and also in my users collection and you see the details here now before I move on and make any of these elements here in the main dashboard like the posts and the profile and stuff I'm going to go back to our code one last time here in the auth section and fix fix up this use auth hook so you notice that previously we just used the auth user and we just got it from the use auth state hook and basically all we're getting in this auth user is all the information that is available inside of this authentication table so we have the email we have the password and then we have the ID that's pretty much it we don't have access to the avatar and the avatar links and the user name and our own custom values that we put in our users firestore collection so let's fix that by implementing some function calls in this use auth hook to make it more robust so what I'm going to do here is I'm instead of just returning the auth user object straight away to the user we're already in the return object I'm going to do some processing I'm going to return a separate different user object that has both the information from the authentication table and from our users firestore user profile table so to do that I'm going to make a different variable a different state variable called user and then here I'm going to do use effect I'm going to change this as loading to a different name because we're going to have two different loading states I'm going to change this to auth loading so every time auth loading changes every time auth loading changes I want to run the code inside of this use effect hook and I'm going to make a function here that's asynchronous and we're going to call this fetch data and in this function I'm going to take the auth user's user ID I'm going to take that ID and I'm going to fetch the data from the firestore database with the ID that I now have and I'm going to return I'm going to make a new user that new user object that has both the user's ID and the email and everything else the avatar and username so here the first thing I'm going to do is set loading to true and I'm going to have my own loading state to fetch the to handle the loading state for fetching the firestore so is loading and set loading use state so here I'm going to set the loading state to begin at true because every time we use this use auth hook we're going to assume that we want to reach a point where we can either determine the user's user profile or the user isn't signed in yet so it'll always be true we'll never start use auth with false other hooks like the use login hook where the loading state begins with false because in the login page nothing's loading in the beginning so it's just it starts to load when you click the button to login but here in use auth it always loads on the page load so we start use state and true and use login is false so here after we set the loading to true we're going to get a reference from the document reference of DB users and an auth user at UID so basically we're passing in the database as the first argument to this document reference and then we're going to reference the user's collection and then this is the ID of the document and in this case the ID of the document is equal to the user's ID the user's UID and now that we have our reference this doesn't do anything yet this is just a reference to a document in a potential document so we haven't sent out an API call to fetch the data yet so now we can use the actual function to call the API and it's called getDoc and then getDoc takes in the reference so I have to import this too so let's import getDoc and then because this is an API call we have to await that and then we can get a snapshot back in the response and then once we're done with all of that we'll go ahead and set loading to be false the problem with this is we're just putting the document snapshot into this constant we're not doing anything with it so what we have to do is we have to take the user and then we have to set it into the state variable user and then we're going to return the state variable user instead of just author user so we're just going to do const const to user no actually let's just do setUser setDocSnap so this is just a snapshot it's just a snapshot containing all of the information and it has a whole bunch of other extra information like headers and other details about the API call that we don't need so we need to call the dotData method on this docSnap this document snapshot to get the data and that data is the data of the document and then we're going to take that data and set it into the user state variable and then we're going to return that user state variable so it's better I guess give it a default value of null because the user is going to start off at null and then this loading is going to be true so what I'm going to do next is because right now we just have an asynchronous function here inside this use effect called fetchData it's not actually doing anything because it's just a function definition it's not the function is not being called so we have to call this function but only if author user is not null and when author loading is false because if author loading is still true that means that author user is still being fetched it's still in a process of being fetched so we don't want to run this function yet so if not author loading meaning if author loading is done and if author loading is done we're going to check if there's a user because if there's a user it means we're signed in we have to spell it right and then if there's no user that means that we're signed out we're not logged in so we just set loading to false and we do nothing here we just say it's we're not signed in if author user is true that means the author loading is completed it's done fetching the user and there is a user then it will run fetchData let's go to the browser and try it out so I'm going to try login with testuser at g.com we do pass password 123 hit login and it says we're logged in but it doesn't redirect this back to the dashboard so I'm thinking what's happening here is if I go to if I go to layout layoutindex.js here and we look at the redirect code it says that if path name starts with protected and not user but the issue is that the user is loading at the beginning and when the user is loading the user is undefined and yes it does return loading auth user if it's loading but this use effect is before this return statement which means that it still runs and it still sees that all users undefined even though it's the user is still loading so one way to fix this is that we can if we can say it's if it's not loading and and then everything the rest so if it's not loading only should you check if the path name is protected and only should you check if the user the user doesn't exist so if it's still loading this entire this entire thing won't run because that's false and then we won't navigate until until is loading is true that means I can just add is loading here I guess in the use effect array so I'm going to refresh this test user at testuser com password 123 login fingers crossed and we are logged in and it doesn't immediately kick us back to the login page which is good work on the sidebar component so you can see here that we have our sidebar and no matter which page I'm on if I'm on the profile page or if I'm in the comments or the home page you can see that the sidebar is always just there and it's constant so that just means that we have to make our sidebar inside of this layout folder and just include it in this layout this layout index.js file here so let us go and make our sidebar .js and just looking the structure of our folders and files I think I'm just going to take the navbar just move it just move it into our layout folder just to ease organization I'm going to update the imports so we have to now import the navbar from component slash layout slash navbar instead of components slash navbar and you can get rid of that folder and just to make sure everything is still working I haven't included the sidebar in the layout component yet I just moved the navbar and that's pretty much all that I did so it should still work and now let's make our component our navbar our sidebar component so we have a sidebar here and I'm going to take some code and put it in here it's going to be a box that's pretty much just the container for our sidebar we can import that from Chakra UI and just to show you what this looks like I'm going to make a red background and it's not going to show up here in the browser just yet because this sidebar is just a component that isn't included yet so I have to go and import the sidebar in my layout component there we go and then here let's just let's see let's just put our navbar somewhere here just sidebar slash alright so that's our sidebar it's on the left side which is on the wrong side and we can fix that with a few styling options here we can just make a flex a flex container and we're going to put our outlet in this flex container or sidebar in our flex container as well and I'm going to wrap our outlet in a box that has a width of 900 pixels and let's move the outlet inside of this box have to import the box as well and then we can style the flex we can give that like a padding top of 16, padding bottom we can give that 12, margin axe auto I give it a full width a max width of 1200 pixels so that's how sidebar looks like and I'm just going to take out the red because we don't need that anymore and now I'm going to go back to my sidebar component and let's go and add some components in here I'm going to have an active user component and that's basically this avatar and this entire component here above the purple bar and that's going to be our active user component so I'm just going to leave that as a comment and then we're going to have to make that purple bar and then the all users button so for the bar I'm just going to use the chakra box as a bar, as a divider and see if that shows up alright so it shows up there and then it's of course going to be pushed down when we have our active user component afterwards, then we're also going to add a button here that says all users so I'm going to put the button here so the button just has like an outline a variant of outline, there are different button types if you look at chakra UI so there's the variants we have button, outline solid outline ghost and link so I'm just using the outline variant, let's comment that out first and yeah so we have all users I just want to find a way to center this if I do the line equals center, see if that works and of course it doesn't work because I'm adding the align center property to the divider box which is basically just like green bar that green bar up there, that's the box I'm adding the center to so it's not going to work instead let me just make another box to wrap everything and put center on this parent box instead it's not going to do anything but if I do align equals the center it should align everything to the center so that's nice next let us actually make this button link the user to the profile the all users page so to do that let's go to our routes folder our routes file here and let's just do export const users equals to protected slash users and we can add that as another child path here, the path would be users element we're not going to have any elements here first so we can just do users a string as an element then here we can link to users and then we can import the users from our routes folder, our routes file and then as link now this link is going to be our react router link which means we have to import that and now if I go back to the browser and click on all users it will redirect us to protected slash users which is just basically a string right now and it is now time to work on the active user component I'm just going to make that this very same file in sidebar so I'm just doing function active user and then it's going to return stack and then we can just active user and then this active user stack I'm going to have code code is just a way to format our username so you see this let's go to browser here that's basically just Chakra UI's code component it's basically for you to write code and show code in your website using that component to display the username in a cooler way so we can simply just type at username for now and you can see that shows up and another thing I want to do is I just want to give a line equals the center here into the stack so that's the center and we can give spacing equals to 5 as well as margin y equals to 8 so it has space above and below the stack as well as between each elements in the stack so like if I had multiple code elements here you can see that it has that spacing without spacing 5 it's just all stuck together so let's reintroduce the spacing and here I'm going to add a button edit profile color scheme let's make it teal and then we have a profile so we have our button there and then I want to make the button have a full width so you see how this is like a long button and this is short so we can always just add width is full and it makes it long and then we can also add a functionality so that it brings our user to the actual edit profile page and as usual to make this button function as a button that will link us to the user's profile page we can do what we have always done which is to add the as equals to link prop so we're rendering this button with the check UI button styles but the actual functional component behind this button is the link that we're getting from React router and then we also need this to prop to know where to go the thing is so the way our URL is going to work is we're going to have something like slash protected slash no alright let me just do it in a string so it doesn't all complete so it's going to be in slash something slash protected slash users or more like protected slash profile slash the user the user ID so if I go to my demo site if I do edit profile you can see protected slash profile slash whatever that user ID is so this is dynamic this is like a dynamic link and we have to go and add that to our router here so I'm going to make a profile profile path export cons profile equals to slash protected slash user slash profile and then here it's going to be an ID so that's basically how you tell React router that this last part of the path here is a dynamic dynamic dynamic parameter which we have to get so that's the ID and then here we'll do profile and then here the element just user profile for a specific ID and then let's do two equals to and then we're going to use a formatted string and we can do protected the protected route slash profile slash and then here we have to add the user's ID and we don't know what it is right so we have to get the current user's ID as well as the current user's username to be able to make this update and not just hard-coded so how do we do that now remember the hook that we made in our hooks and auth here we have our use auth so right here use auth it will return as a user object and it's loading state so here within the active user component I can do user and it's loading equals to use auth and then here instead of just hard-coding username we can do user.id and the problem with this is when the user is loading user is going to be undefined and undefined doesn't have a property of ID doesn't have .id so I'm going to do like if it's loading then we return just loading I guess and then here we can do user.id and then we have to add a question mark behind the user variable because just in case the user doesn't have the user is still undefined it's going to throw an error like if I just ignore oh meet that and let's just see if it gives us an error I'm going to go back to our app here and refresh this so it's I mistyped that it should be user. username not user.id and it should be test user so it works and if I click edit profile it's going to bring us to slash protected slash profile slash whatever the user ID is so I was wrong I don't we don't need the question mark there then this works because this this early return state modes will stop us from rendering this component that doesn't when the user isn't defined yet and now finally let's add the avatar above the user name here I'm going to use the avatar component from Chaco UI and the good thing about the avatar component is that if I if I add so usually you would have to do a source and then give it like slash give it like slash images slash avatar.png or whatever the source is right but for Chaco UI for Chaco UI is the avatar component if you just provide it with like right now if I don't provide provided with anything it's going to just fall back to that default avatar picture if I give it a name of like um tl you'll see t show up the initials will show up like I believe if I do tl space a it's going to do ta let's do like c does it show three characters no so I guess two characters is the limit the max limit because one for the first name and one for the last name so if I did like Donald Duck it should it should do dd all right so instead of just giving it hard coding the name to be Donald Duck we can change the name to do user dot user name and then if our user is that's if our user is test user and then it should be a t that shows up here and I'm going to increase the size of this avatar to make it something like XL so it makes it bigger and also the one more thing we're going to do is instead of just using the letters as the I just want the letters to show up as a fallback like just in case the user doesn't have a profile picture but if the user does have a profile picture and if I go to my fire base here and I just add a profile picture this to this avatar field I want it to be I wanted to show up so I can just go and go for a user profile picture image and that's we're going to we're going to implement fire base storage to enable users to upload their own images by the end of the tutorial but for now for demonstration purposes I'm just going to just google just like right click copy image address just put it in here in our avatar let's put it let's update that and then right now you don't see the avatar show up so you're going to make the source here equal to the user dot avatar and it should show up and it gives us that updated avatar one final touch up I want to do this avatar is that look when I hover it doesn't do anything to my mouse and I can't click it and when I click it nothing happens but if you look at the app here in my demo I can click on the avatar it will bring me to the profile so if I just click on it you can see it brings me to the profile so I'm going to just add a few styles here you can use the hover the on hover target in Chakra UI to specify styles to add when the mouse is hovering over the object so I'm going to make the cursor a pointer that basically just means the cursor becomes like a clickable cursor I'm also going to give it like background opacity maybe opacity of 0.8 percent like 80 percent and it's going to reduce the opacity so it makes it more it makes it feel like it's a clickable object and right now it's not going to if I go home I click on my avatar it does nothing so you can always just do as equals to link link and then do 2 equals to whatever destination you want it to be but I already have that in my button down here and I don't want to just keep adding as equals to link to everything so another way of implementing the link functionality to all of these components I just want to wrap this entire section in the link component so I can just take this out and just do a link and then we just wrap the entire thing and get rid of the ass prop just take the 2 and just put it here in the link and just save this so no matter what I click inside of this link component no matter if I click the button, the code or the avatar I should be able to just go to the link so if I click on the avatar it brings me to the link and that's great now I noticed that that messed up our styles a little bit here so that's because we're messing with the stack component we can just move the link outside of the stack component and now that should fix the styles and we can click anywhere in the stack and link us to the profile so I can do that and link us to the profile maybe this isn't that optimal because if I go home and I click on this empty space and not on the avatar itself it will still link me to the profile so we might want to fix that so the way I'm going to fix this is I'm just going to revert back to what we had originally and make the button a link just have that here in this avatar we're going to make this avatar as a link and then we're going to send it to somewhere and I'm going to take the avatar and put it out in its own separate component because if you look at our demo project here we have avatars in a lot of places in our project we have avatars here in the sidebar we have avatars in our posts and we have avatars here in our all users page and in our let's see in our comments here as well so we have avatars in a lot of different places and just to have our one avatar component in a different file we can just reuse the avatar component in multiple places so I'm going to make a new folder here called profile profile because we're going to have a profile around later on anyway we're going to have profile slash whatever and we're going to have an index.js in this profile at some point but right now I'm just going to put the avatar in here and let's do a react functional component and then we can return this avatar and then we have to import the avatar. I'm just going to comment this too and then we have to import the link as well so let's import our link and let's import avatar because the avatar this component has the same name as the function so that's not going to work. I'm going to do chakra avatar here and then we can do import avatar as chakra avatar and then here we're going to have to get the user from the props so we have that and then let's just say user if not user and then we're going to return loading because the user could be loading here and we don't have access to the is loading prop here so we just detect if the user is null then you just return the loading and then here instead of doing that here I'm just going to take the user and put it in the avatar component so avatar and then the user equals the user you have to import the avatar not from chakra UI but from our own component so we import avatar and then let's fix this too so to equals to our formatted string the base is going to be the profile slash profile slash and then the user ID there we go so can't read properties of null so I'm going to have to add the question marks I was talking about earlier to the user variable now if I refresh this it should it still says null let me check let's just add the question marks everywhere and fix the problem and you see that our mouse we can't click the empty spaces out here anymore and we can click the button or the avatar if I click on the avatar it's going to bring us to the profile wait a minute this this link isn't the right link that we want because we don't want a colon ID appearing in our URL that's just for react router the parse in the backend so I feel like we've done something here yeah this shouldn't be profile here it should be protected so the reason why I was doing that is because if we look at our routes here and we have our profile this string right here is just to be put here for react router to parse that and just understand that the last part of the URL is the ID and we're not supposed to actually put that in our link so I'm going to save this and if we go back and just click on the avatar it brings us to profile and another thing I want to do is I want to get rid of all of these question marks because it isn't a good practice to be adding question marks everywhere just because you never know it's unpredictable and you never know if the user is going to be undefined or not so just doing question marks everywhere I'll just get back this loading state here if it's loading and then we just return the loading and just get that back and see if that works and refresh that let's hope it works, I'm going to edit profile it works and then if I click on the avatar that works as well so that's much better that's better practice I'm going to take a break from all of our user profile editing and profile pages and go and backtrack to our dashboard component so our dashboard component is going to have a section to add new posts and then we're going to have a list of all of the posts just on the feed in our dashboard so I'm going to make this new post component first and let's go back to the code here in the dashboard in x.js and let's replace this so the first thing I'm going to do is edit box and then I'm going to give it a max of 600 pixels give it some margin and padding and here I'm going to have a form and that form is going to be for this input here alright and then in here I'm going to have just a horizontal stack and then I'm going to have a heading that says new post and then I have to import that from chakra and let's refresh this doesn't do anything right now so I'm going to go and look at our routes maybe it's because that's because we have the string here as our dashboard element we're going to do dashboard instead and we should see our new post and that's nice but I feel like I want to downsize the heading let's change the size to something a bit smaller and that's algae and that looks perfect and the next thing I'm going to do is I'm going to add a button here at the end of the new post like to the right of this new post title that's the post button that you see there so let's go ahead and make that button it says post and import this then let's see so we have our post button I'm going to have to make it all the way to the right though so I'm just going to give this h stack justify space between and that should make it all the way to the right and let's give this button a color scheme teal and we're going to do size of medium margin top you know what before we do all of that let's see if that looks yeah it looks pretty much the same so I don't have to add any of the other props but one very important thing I forgot to add here is the type of submit to this button because I'm going to be using react hook form again to deal with the form here and to run the handle submit function and stuff like that and if we don't put this type of submit here to this button react hook form doesn't know that this button is the submit button and it won't probably won't handle submit if we click on this button and the next thing I'm going to do is I'm going to give I'm going to make a text area so chakra UI has this text area that we can we can resize like that for some reason stacked next to you yeah it because that's because it's in the H stack I have to take it out of the H stack and then make itself closing and should be below and we want to get rid of that that adjustment handle there so what we can do is we can do resize equals to none and then what I'm going to do is give it margin top let's give it margin top of five and that's going to space it nicely and I'm going to just refresh refresh this so what you're going to notice is that when I when I go down it's going to it's going to scroll and that's not what we want because like if you look at our demo app here you can see that it automatically resizes and that looks aesthetically much more better and it looks much better so we're going to use this package from npm called react text area auto size which uses jQuery to automatically resize our text area input and some it's just a fancy little detail that we can just add with yarn and then while that's running I'm just going to add some I'm going to add a placeholder here create a new post a new post there and then let's restart the server and to use that component in here I'm just going to use the ask prop again so ask text area auto size and you have to import this so let's import there and then if I refresh this now if we type stuff it automatically resizes which is perfect another prop that you can pass to jQuery UI's text area is the min rows prop it'll just make the minimum number of rows larger so if I do 10 you can see the minimum rows is it's going to be 10 but I'm just going to leave it at 3 the next thing we're going to do is just implement the react hook form hook called use form like we have done for the previous forms so we're going to do const and object equals to use form and then we can get register from here we're going to register this text area as an input so use the spread operator on the register and here we can just do text and then here we can have some validation which is pretty much just do require equals to true and that's all of the validation we're going to do for our text in our post we're not going to make another validation function for this one and let's import use form so let's see if the auto import works it does we can also get handle submit as well as reset from our use form hook and here the form can do on submit equals to handle submit let's say handle post and then we have to make that function async function do we actually we can just do a function handle post to add async if we have to make an api call afterwards and here let's just do reset we're going to get the data object and we can console log and see what it looks like again so basically this is pretty much like our previous example the data object is going to come from the handle submit function from the use form hook and reset just basically going to wipe the form to its original state let's go to our browser and just try it out so I'm going to do whatever here let's hit post and here you can see the data object that's console that's logged into the console and basically we have a text prop that has the text yeah so instead of just logging that to the console we have to actually post this and upload this to the database and for that I'm going to use another one of our custom hooks and I'm going to make a new file in our hooks directory called posts.js and here we can finally make our first react hook that doesn't have anything to do with authentication unlike use auth use logging or use register and then we call use post use add post so export default export function use add post and we're going to return a function here to add post as well as the is loading state and then we have to make our async function add post and this function is going to take in a post object and so we're going to set loading to true here when we first start to add the post and that means we're going to have to make our state variables so we have to import use state and then we're going to just set loading to true then we're going to we're going to make our post inside of this add post and just like our register use register hook where we are making we're adding new documents to our users file table in Firestore we're going to use set doc instead of add doc because I don't want to rely on Firebase to create random document IDs for me and I want to be able to make my own IDs and have more control over it that way I can create documents and add the ID field into the documents themselves so I don't have to worry about getting into the document ID later on so set doc is an async function so I have to await that I'm using the doc reference here in the first argument and it takes in the document object as the second argument so document reference I'm going to make using the doc function this is basically version 9 syntax for Firestore Firebase and the first argument for the document reference is going to be our database handle so db and the next is going to be our collection name I'm going to name it posts just like our sample database if I go to the test social media app test down here so that's the name of our collection it's called posts and it's going to have all of the different documents and here you can see we have the ID field in our document so usually if you use add doc it will just generate a random document ID and you won't have access to the ID field inside of the document itself and you have to use like snapshot.id to get the ID and you can't just there's more there's extra steps involved so I just prefer to add the ID into the document itself so I'm going to do ID here and then the ID I'm going to make using this library called uidv4 from I guess we can just try the Firebase util uidv4 function to see if it works because usually we have to install this other library to make our UIDs worse and if this works then we don't have to install that so in this object I'm going to use the spread operator on the posts on the post object there and then I'm going to just inject the ID there I'm going to inject the date which is the date created as well inject a likes field so likes is going to be an array and this array is going to store all of the user IDs of all of the users that liked this post so when we do a new post it's not going to have any likes yet so it's just going to be empty and date can be date.now and I'm going to see if this works let's go to our handlePost you know I'm going to rename this to handleAddPost so it's less ambiguous and then I'm going to make our hook here let's do addPost equals and then we also need isLoadingUseAddPost and then let's go to our button here and change isLoading equals to our addPost one thing I forgot is when I'm using the addPost function here I have to pass the UID the user ID and as well as the text the text I can always just get from that other text which is coming from the react hook form data object but UID this so basically this ID that you see here is the ID for this document this post the ID for this specific post but here we're going to have to add a UID UID for the owner of the post the poster so the user ID of the person who posted this post so for that I have to go and get the current user object so I guess we'll just use our user or use auth hook that we've made and I can call isLoadingToAddPost add addingPost yeah and then here authLoading so we have two different loading states and here the UID is just going to be the user.ID and one thing to notice is that when the user is initializing is loading the authLoading will be true and the user will be undefined and if we try to add the post here it's going to give us UID of undefined which we never want so we want to limit the user to only be able to post and submit this form once the user is done initializing so here I can use the isLoadingProp to say if if authLoading is loading which means the button should be loading in the loading state which means it's disabled and it's spinning and then I'm going to do addingPost here as well so let's do loading text equals to just loading so we have to import use auth as well let's import that so technically this should work if I go over to our React application and try to add a post it's not going to show up here in the space below just yet because we haven't made the component for the post list but we should be able to go to our Firebase console and see the collection here appear and the collections don't exist in Firestore like the posts collection doesn't exist yet and you try to add a document to that collection Firestore will automatically create that collection and add the document inside of that collection so let's make new post hit post it's going to be loading and then I'm going to go and see if it updates the Firebase console so we do see our posts collection appear and we do see a new document here and the form field is reset and that's how we know that the reset function has ran but the button is still in the loading state and that's because if I go to my posts hook you can see that I set loading to true but I never set loading to false which means I'm going to have to set loading to false here and then I'm just going to add a toast I'm going to go and grab a toast and just put it here just put the toast here and then just to notify the user that they added the post successfully and I'm going to const toast equals to use toast there if we refresh this and we do this is another post and I hit post there we go the post added successfully and then the field is reset and we can go to our console and we can see another post showed up so now let's go and make our post list so we can actually see the post that we've added to the firestore database I'm going to go to our files here and just make a new folder here called posts or just post and in this post I'm going to make index.js and this is going to be one post it's going to be the component of a single post and then we're going to have another component for the post list so I'm going to make that post list.js so this is one post and this is all of the posts I'm first going to make one post and the import react can do post so I'm going to have a box and padding let's have padding of 2 I'm going to have max width of 600 pixels and then in this I'm going to have to import this box from chapter UI as well and then here I'm going to have I'm just going to find a way to render this post to the browser first we're going to make our react function component this post list a post list is going to take in all of the posts and then we're going to return post.map now actually let's just return a box here and then I'm going to give this box padding x of 4 units and then we're going to do posts.length equals to 0 so if the post length is 0 then we're just going to print something out here just say like no posts or something and if the post length is not 0 which means that it's greater than 0 then we're going to do posts.map and we're going to map for every post we're going to return a post and then of course we have to give it a key value here or else react is going to complain because we need every time we use .map we have to add a key to each individual post then we're going to pass the post data object because remember that our post is expecting some data and we can destructure this post data here and just we're going to get some information from this post object and we're going to worry about that later so the key let's just do key is post.id because each post is going to have an id and we can import this post from .slash index right and then here we have to import the box as well let's do that let's go back to our dashboard and below our new our new post component we're going to make another component here for the post list what I could do is also just take this and make it in its own own component so function new post just take this entire thing just return this here just return that and then we're going to have to take all of that and bring it there in this new post component and I'm also just going to just do new post and then here post list so right now it's not going to show anything yet even though we have this if post length equals to zero it's going to show no posts and that's because posts itself is undefined and undefined is not equals to zero so I guess we just have to go to our dashboard here and just give it a mock data of an empty array now we should see no posts we're going to make this a little bit more aesthetic by giving this by making this a text component from Chakra UI post yet dot dot feeling a little lonely here and we are going to give the font a size XL looks better and then we're just going to do text align center so now I'm going to go back to the code and just go to the post component and let's add something into this box I'm going to add this I'm just going to paste this code in and basically what I've done is I've added a header a box section and actions so I'm just going to comment out the header and actions we don't have to worry about that yet basically what that's going to be is this upper part here that's going to be the header we're going to have like the date the time posted and the user who posted this post and then the actions is just bottom bar with the like button and comment and if you make it new post it's going to also have that delete button if you are the owner if you're the original poster so import the text from Chakra UI and just see how this looks so basically what this is is it's basically just breakpoints and we can just we can just set the font size to medium for now and if I go back to my React app and it's still not going to show a single post because if I go to my dashboard you can see I provided posts to be an empty array and when it goes to the post list it's going to just look and see that the post length is zero just return this and instead of just mapping through the post I can just give it like mock data and just do one two three blah right and it's going to give us any number of posts there so what I'm going to do now is I'm going to change the text here to reflect the text that's in our post here so this text value from our Firestore database so to do that let's go ahead and write another one of our custom hooks inside of posts.js so just under add post just under use add post here I'm going to export another function called use posts and here I am going to just make a query to the database all of the posts and just list them out so as usual I'm going to make a constant queue which is the query for our posts and the collection I have to import the query don't I I have to import this from Firestore there from Firestore then we're going to query in the first argument is always the database handle and then the next is going to be our actually I'm just going to do collection here and the database handle inside of the collection and the name of the collection is going to be posts and then I'm going to use reactfire base hooks again for this I'm going to go and look for the top use okay this is not the right this is this is for auth I have to go look for cloud Firestore hooks just look for use collection data just copy so we can just use collection data so const we get values loading error snapshot so posts is loading and then equals to use collection data and we have to import that from we have to import use collection data from reactfire base hooks slash Firestore and then here we have to pass the query in so I'm going to put Q and then let's also just get error because we can get the use collection use collection data we can get values loading error in snapshot so let's just get the error and if there's an error we can just throw the error so we can see the error in the console and just fix it and we can return the posts and is loading so if I go to my post if I go to my dashboard here and I do const posts is loading posts loading equals to use this is not even the right place to do it I'm sorry this is in the new post component I'm going to be doing this in the dashboard component use posts and I have to import this so instead of just hard coding the posts I'm going to do posts here and just go to our post list and see if everything works and we're getting the posts here and we're putting the posts to our individual posts and here we are going to just do the text and we're going to destructure the text from the post object so if I go back to Chrome and I go to my app you can see that it shows this is another post and new post and that's because in our firestore database we have this is another post and we have new post and if I go and add another post here let's do that it goes to the bottom of the list I can add more and sometimes it goes like in between the posts and that's just weird we don't want that we want the newest post to be on top and the oldest post on the bottom so we can modify or hook in our vscode posts use posts hook and here in this query I can go and modify this and we can add the order by clause and you have to import that from firestore so we can order by the date this is why we created that date that time stamp that date field and we can order by ending so now you can see the newest one always goes to the top this is the newest post it should go to the top there we go and I'm going to come back to my dashboard component here and I realized I'm not using this post loading state so I can just do if is loading then we'll return loading loading posts and the next thing I'm going to do is I'm going to fix this thing so I'm going to go and make this header.js component and let's go and close out the rest of the things that we don't need so this is going to be a react functional component and that's I'm just going to put the container in here it's going to be a flex and we have to import that from the chat and like if I go to the browser right now we don't see anything new because we have to import we have to import and use the header so import header and let's use that so we do see that small header appear and I'm going to add a few things into this header first of all if we look at our demo app we're going to have our avatar and remember that we already made that avatar component inside of our profile so this avatar here we can just import that and use that here so import avatar and just use the avatar here and one thing to note is that this is going to give us an error because avatar here it expects us to give it a user object and we can't just get the current user with use of the use of in here and just put the current users into the avatar here because as because you can see that the user depends on the owner of the post the user ID of the poster and not the current user itself so we have to somehow get the post to get the user ID in here in the header and then just use that to get the details from Firestore like the user's avatar and the user username so let's just do UID and here we're going to go to the post and provide the UID here so this is the ID of the poster and then the UID is something that we can get from the post we can destructure that from the post object because if you look at the Firestore database in the post we have the UID field which contains the ID of the owner so let's save that save this and right now we don't really have a way to get the user's information that's why we're going to have to make another hook here I'm going to make a new file called users and here we're going to have all of the user related hooks so let's make this user user let's take in the user ID this hook is going to be pretty simple because all we have to do is read the document in the user's Firestore collection that contains all of the user information that we need so let's react firebase hooks for this we're going to use the use collection data hook again so we can do const we're going to get the user and the user basically just is loading and then error we don't even need error I don't think we can just omit that and we just use document data and then here it's going to take in the query and we can just make that query constant so query it's going to be a document reference and in here I'm going to have to close that and in this document we're going to pass in the database handle and then we're going to pass in the collection name which is users and then the ID and see the formatting is right do I need one more right doc is just not imported so I have to import that and then we can just return the user and is loading that should pretty much be our use user hook that's all we need so I can go back to my header component here and we're getting the UID from our from our post because we're passing in the UID to our header so now that we have access to our user ID we can just get the rest of the user information and just pass it into this avatar here so we're going to pass user here and we're expecting to get that user object so we can just do const user and then is loading equals to use user and then pass the UID I have to import this and let's say if loading return loading that should work if I go to my browser and you see that we have our user and we can always just look for sample a dog image and just like just get one of these images let's just go and copy image address and just like change the avatar and you can see it changes the dog picture to the avatar and one thing is that this avatar is a bit too huge and if I go and do size equals md here it's not going to do anything because this avatar is not the checker UI avatar component it's our own custom avatar component it's just a profile here which means I'm going to have to manually take the size in let's have the default size to be XL instead and just put size equals to size here so if we don't specify a size in the props for our avatar component it's just going to default to XL but if we do so choose to override the size with our own custom size then that will work you can still see that this is XL and this is M I believe the next section I'm going to add is this user profile and then the date like how long ago was this post added so let me go and take that piece of code and just put it down right beside the avatar it's going to be a box that has a button for the username and the text for how long ago this post was created so I'm going to import that let's import that and import the text as well so if I save this you can see that we have our sample username I don't even need the ELISA it's just a sample username and then nothing happens when I click on it right now and it's just giving me the sample username and not the actual username yet so let's go ahead and make this print out the actual username so remember we have access to this user object I can just do user.username so there we go we have our test user it's just hard coded right now so what I'm going to do is I'm going to get the date from the post so here instead of just passing just the UID I'm going to be passing the date as well and the date is something we can destructure from the post as well that's the date created it's going to be a number, it's going to be a time step and you can get that from our post document you can see that each post is going to have a date and that's coming from our post use add post hook and remember when we made new posts we always add the date property and it's going to have date.now in it so that's going to be the time stamp of when the post was created so now that we have access to that date I'm going to install a new library it's called datefns so datefnsnpm so this is the library that we're going to use to format the date because we have to somehow convert this time stamp number into a string, a readable date for humans to read and so we're going to just npmi datefns or we could just use yarn so let's stop the server yarn add date-fns and once that's done installing I'm just going to go here import format distance to now from datefns just yarn start and then here I'm just format distance to now and then date and you can see that it's working it's 18 minutes ago, 19 minutes ago, 42 minutes ago if I make a new post right away and I hit post you can see less than a minute ago and that's just going to automatically format and update