Build and Deploy a Full Stack Social Media App | React JS, Appwrite, Tailwind CSS, React Query

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
this is not your typical Instagram clone we're bringing you a modern social app with stunning UI with a native mobile feel a special text stack an infinite scroll feature and amazing performance have you ever struggled with complicated server setups worrying about security handling user off scaling managing and storing files securely and optimizing API performance without losing countless development hours if that is the case Cas you're not alone and I've got something that can help whether you're a new or a season developer thinking of starting a fresh side project doing all these things on your own can be quite a hassle so hi there and welcome to a new project video where you'll build and deploy an amazing social site with a hassle-free backend thanks to aight Cloud it allows you to create a backend faster than Thanos snaps his fingers and at a much lower cost than scary Firebase for pro plans you'll get what you would otherwise have to pay in Firebase for free with aite but what are we building the app you'll build contains a robust and stunning authentication system a homepage for exploring posts shared by others with top creators featured on the right the ability to like and save posts accessible through a separate dedicated page and you might think here we go again another Instagram clone but trust me this is not your typical app sure you've probably mastered the basics of crowd operations but have you ever had a chance to implement that one incredible feature that's had us all hooked for decades yes the infinite scroll we'll implement it inside the explore page integrate it together with the sech functionality and I will teach you how to do the same for all other Pages too and moving to other phenomenal features will develop a detailed post page that also displays related posts a profile page showcasing your liked posts and the ability to edit your profile similarly browsing other users and their profiles a create post page for sharing all kinds of memories you would like to share with effortless file management and storage and a drag and drop feature an edit post page to edit the contents of your post anytime and so much more with an amazing responsive UI with the Bottom bar that surely gives the feel of a native mobile app does it sound exciting as it does to me we'll develop all of these all well learning react react context API complex react routing with outlet and conditional rendering we'll use the latest version 5.0 of the backand agnostic data fetching Library famously known as react query now t stack query that will allow us to implement autoc caching ref fetching parallel queries a first class mutations loading State Management and more then you'll also learn Tailwind shaten ight Cloud as a backend as a service tool and everyone's favorite typescript there is a lot to learn so I hope you're pumped to learn these exciting features and master the Most Wanted skills to impress potential employees ERS and clients with that said before we dive into the development of this app there's one more thing that we must do and that is set up an account on aight Cloud so right now click the special link in the description that's going to allow you to follow along with this video and create a phenomenal backend with an aight Cloud once you click it their homepage is going to open and then you can go to sign up once you're in you can sign in or sign up the simplest way to do it is using GitHub once you're in you'll have to create your first project use JSM to start with and then add an underscore and add your app name I'm going to choose snapgram but you can choose anything else maybe something with just a bit more imagination and then click create project and we are in operate cloud is going to allow us to create robust secure and scalable backend applications it provides sdks and server functions that you can integrate with with any kind of framework some of the best features they offer and at the same time the features we'll use to create this project are o where you'll be able to add specific team-based and permission-based security they offer o options from email and password to Magic URLs and more than 30 social sign-ins the next thing we'll use in our project are going to be databases you can add more than one database for a specific project in the process of creating it is super simple then you can of course add many different Collections and the best thing is each collection has its own attributes which can be of a lot of different types and you have advanced permissions on a collection level the next feature I'll also teach you how to use is storage it allows us to quickly create buckets of different files where we can store any kind of images and even export them and transform them to reduce file sizes and finally there are cloud-based serverless functions and the best thing about aite is that it offers all of these features for free setting it apart from traditional backend diservice Tools in terms of pricing and value and because of that it's no surprise that aide has become a trending project on GitHub so now that you're set up with aide and hopefully excited for what we're are about to build together let's Dive Right In to get started with developing our phenomenal in Instagram clone application we can start by creating a new empty folder on our desktop and let's call it snapgram once you created it you can simply drag and drop it into your code editor of choice in this case Visual Studio code once you're there you can go to the top go to view and then terminal this is going to open up a built-in integrated Visual Studio code terminal lately we've been doing a lot of next year yes so I'm quite excited to get back to react a bit we're going to use vit which is the fastest way to set up our development environment for react so head to VJs dodev and click get started once you're here you can scroll down a bit and you can see that you can initialize your V application by running mpm create V at latest so paste that Command right here add a slash to create it in the current snapgram repository we're in and press enter this is going to ask you whether you want to install the create feed package to which you're going to say why or yes and then you can choose which type of application you want to run in this case we're going to choose react we will use typescript so you can press enter and that's it you can run mpm install to install all the necessary dependencies and then mpm runev to see it in our browser the installation usually takes just a couple of seconds so let's wait for it and then we'll be able to run the app once it is done press mpm run Dev this is going to spin up our application on Local Host 5173 and you can see it took less than a second to spin it up so hold control and then click right here to open it up once you do that you'll see a simple V and react starter this means that we are ready to get started with creating the base file and folder structure of our application so let's start from beginning here we have our source inside of which our entire application will be here we have assets which we can move to the public folder just to clean up what we have in the source we're going to have a couple of different CSS files but for now I want you to delete everything that's inside of the source as a matter of fact let's delete the entire Source itself because we're going to recreate it immediately after so create a new source folder so we can start from scratch and the main point of cont we need here is a file called main. TSX this is the starting point of our application where we can import react from react and the only file where we're going to import react Dom from react Dom as well once you've imported it you can say react dom. create root this is the root or the starting point of our application so we have to Target our root by saying document. getet element by ID and we pass a string of root and then you say. render and inside of here we can render a self-closing app component of course this app has to be created and imported from somewhere so let's create a new app. TSX page this is going to be our primary router component so inside of there run ra Ace this is a shortcut to create a react Arrow function component if this didn't work for you you might not have the necessary extension to do so so head to extensions and type es7 plus react Redux react native Snippets install this package and then you'll be able to run that command as well with that said we can now import this app within the main so let's simply doubleclick this app and press control or command space that's going to open this up which is going to allow you to just click it and Auto Import we're going to use this functionality many times throughout this video so you'll get used to it one thing that I noticed is that create root doesn't exist in react Dom and that's because react Dom has to be imported from react-dom SL client and then here this is potentially null so we have to also add an exclamation mark at the end so typescript doesn't complain and no longer are react Imports necessary so with that we have our main and we have our app these are the starting points of our application if you go back and zoom in really closely you can see our div that says app now I know that this is a pretty simple start and you might already know how to set all of this up but let me just remind you that what you're about to build today is extraordinary it's not something you've built so far we're going to use the best Technologies today to create a complete comprehensive Instagram clone with liking saving top creators functionalities and much more so just keep watching and step by step we'll get there and you'll know how to create this application from scratch now that we have the app we also have to have some basic styles for that we're going to create a new file called global. CSS keep in mind that all the Tailwind styling that we'll be doing through this video will be done by you directly within components but we have to have some helper classes here to make her life a bit easier so in the description down below you can find a GitHub gist that contains a global stat CSS file copy it and paste it here you're going to notice that here we have some helper functions for the top bar for postcard image and so on which apply multiple Tailwind CSS classes so if at any point you want to see what a grid container is it's simply a set of utility classes to make that grid container possible so with that said we can import the global. CSS right within the app by saying import. global. CSS but hey this global. CSS file is using Tailwind so let's go ahead and let's set up tailwind and if you haven't heard of Tailwind Tailwind is a phenomenal utility first CSS framework pack with utility classes to make our styling simpler it doesn't impose rules like UI libraries do but rather it allows you to create custom Styles much more quickly so let's click get started and let's install Tailwind CSS but we can also search for V this is going to tell us how to install Tailwind with vit we first have to run mpm install DD Tailwind CSS post CSS and auto prefixer so back in our app you can go to terminal and let's go ahead and open up a new terminal window and within here simply paste it and press enter this is going to install the necessary packages for us to be able to style using Tailwind once that is done you can also copy and paste the next command MPX Tailwind CSS in it- P this is going to initialize and create the necessary projects such as the Tailwind config JS next you have to configure your template paths so simply copy the content from here and go to Tailwind doc config.js once you're there simply modify this content to what we copied from the documentation finally add tailing directives to your CSS that's going to be within the globals and we have already done that with our Global CSS finally run mpm run Dev and then you can style your hello world with a couple of classes to see if it works so back in our app we can now modify the app to say hello snapgram let's save it and back in our app we can see that this is now on H1 but the styles don't seem to be applied if they were getting applied we would be able to see the underline so to make it work there are a couple of things we need to do alongside the globals we also have to modify the Tailwind doc config.js to include some additional theming options for our great application so in the description down below you'll be able to find a modified Tailwind doc config.js file which you can simply copy and then paste right here it's going to include some font families can use widths screen sizes but more importantly colors so every time we want to specify this dark color we don't have to say 0909 08 we simply say dark 2 and the second thing we have to do to make it work is if you notice here we're importing something known as Tailwind CSS animate so copy that go to your terminal and then you have to run mpm install dasd and then Tailwind CSS animate this is that extra plug-in that's going to allow us to play with just a bit more animations it quickly got installed you can go back to your application press contrl C to stop it from running and finally rerun the application by running mpm run Dev and quickly our application is up and running on Local Host 5173 and we can see that this H1 is indeed underlined which means that the Tailwind styles are getting properly installed and we can also see the dark background which means that our base styles are getting properly applied and in a nutshell that means that Tailwind has been properly set up so what should we do next well let's set up the base routing of our application by creating a couple of routes and there for a couple of pages and in react to do the routing you have to install an additional package by running mpm install react router Dom the only package you need to manage the routes once it is in installed we can head to the main. TSX file here you can import something known as a browser router coming from react-router-dom and then we can wrap our application in a browser router just like so there we go the app is going to go within it this means that now the browser router is going to control the routing for our entire application which may makes our ab. DSX that much more powerful because now within here we can import routes as well as a route from react router Dom once you do that you can wrap everything in a main section we'll be using HTML 5 semantic tags all across the video you can also give it a class name equal to flex and h- Screen meaning it's going to take 100% of the screen now you can see how I quickly hovered over it and I can see exactly what CSS properties have been applied this is a pretty cool extension for Tailwind so if you don't have it already just type Tailwind CSS intellisense the first extension that pops up install it and if you're not a fan of Tailwind you can still follow along but you'll know exactly which properties are getting applied for the ones that don't get this hover you can simply search them here here and then you'll be able to find them within global. CSS with that said we can wrap everything in a routes parent within the routes we'll be able to Define two types of routes public routes and also private routes public routes are the routes that everybody will be able to see the sign up and the sign in and private routes are the routes that you'll be able to see only if you're signed in so let's create our two first routes let's do a route which is going to be a self-closing component that's going to have a pth of SL sign in and it's going to render an element of sign in form it's going to be a self-closing element now of course this is a page or a component which we have to import inside of here and we can also repeat this with our first private route so we can say route self close it give it an index this means that this is the starting page and then the element is going to be a home component so we can put a self-closing home component right here now of course we have to import these components from somewhere so let's create the structure needed to do so in the source folder we're going to create two new folders one is going to be called _ o and the other is going to be called underscore root these are two folders that are going to make it simpler for us to know what is public and what is not within oth we're going to create a new folder called forms and within forms we're going to have our signin form. TSX where we can run rafc this is going to create a simple signin form component Within forms we can also create another one which is going to be signup form. TSX we can also run RFC and outside of forms but inside of underscore o we want to create a layout o layout. TSX and there we can run our efce as well this layout is going to wrap both of our signin and sign up forms it's going to have things like the logo as well as this wonderful image gallery that appears on the right side and then the forms will change depending on the URL how cool is that that's why we have this generic layout but then components are going to be the ones that change the form and we're going to have a similar thing for our root within the root we're going to have a folder called Pages within Pages we're of course going to have our home. DSX where we can run rafc but outside of pages we're going to have have our underscore root that's going to contain a root layout. TSX or we can also run RFC and of course the layout for the homepages is going to contain things like this sidebar on the left sidebar on the right and more now within root Pages we're going to have many many different pages I mean tens of pages by when we're done with this application so we don't want to Simply import each one in a new line so we can create a new index.ts file which is going going to allow us to import them in a cleaner way but first we have to export each component we have so we can say export default as home from slome and now we can close all of these new open files go back to the app we can automatically import signin form fromo forms signin form and import home from root Pages while we're here we can duplicate our signin routee and simply exchange it for sign up and here we can say sign up form which we can also import from o forms now notice how for the O forms it imported them as default Imports whereas for the home it imported it as the named import which is going to allow us to later on import page one page two and all the other Pages within a single line to keep our code more tidy great so now we have the base structure and you know how the routing is going to work but there's one missing piece we haven't utilized our layouts and the react router Dom allows us to do so easily you can create a new route just like the routes you created before but this time it's not going to be self- closing it's going to accept an element which is going to be the O layout we created which you can automatically import from o layout and then with in it we can place additional elements or pages that are going to appear there how clever is that it allows you to use the layout but then immediately place the pages using that layout within so we can repeat the same procedure with our private routes as well where we're going to have a route and there we're going to have an element of root layout of course it has to be defined as a self-closing component and then we can place all of the home routes right here great so now you can see we have a lot of imports already but we have done a great job in setting up our path for Success so now going back to Local Host 5173 the only thing we can see is the root layout but soon enough you'll be able to see much more than that so how would you feel if I told you we're going to start with this completely custom and stunning sign up and sign in script screen after all for our social media app to work we first have to onboard our users that are later on going to upload their posts most likely it's going to be cat photos as it usually is on the internet but that's up to them it's up to us to allow them to do so on a beautifully designed and fast platform so let's jump into the signup form the first thing that our user will see our signup form will be just that a form and in this application we'll be using Shad CN styling Library it is a library of beautifully designed components that you can customize using Tailwind everything from dashboards cards tasks playgrounds and of course forms you'll be able to create wonderful but also simple and minimalistic forms everything you need is there so to get started with chat CN we can head through their documentation and then installation in this case we're using vit we already set up the project and we already initialized Tailwind next we have to modify our TS config.js by adding this thing in paths so we can open up our file explorer and then go to TSC config.js so press copy right here go to your file explorer and then go to TS config.js right here below linting we're going to add a Shad CN note and we can paste the base URL as well as pads but don't forget to add a comma right here next you have to install types node so that the V config can resolve paths without errors for that we can open up terminal paste it and press enter once installed we can also copy our paths and then go to V.C config.txt in it let's press y to install it and then we'll have to answer a couple of questions we would like to use typescript yes we would like a default style yes we're going to use the Slate Coler our Global CSS file is within Source SLG global. CSS so we have to modify that we do want to use CSS variables our Tailwind config JS file is located right here so we can simply press enter and we can press enter for the import alas as well for utils 2 and we do want to use use react server components and we can write a configuration so simply yes yes yes enter enter enter and then y to submit it this is going to install the necessary dependencies and then we'll be able to start using shaten components that's it this was the last step right here now a big difference between shaten and other UI libraries is that shaten with this config didn't add absolutely any code to our project it will only add the code and the component components that we actually need so we'll have to manually add every single component we want to use so let's use their button example to start with copy this command paste it in the terminal and press enter it's going to say installing button and if you pay close attention you'll be able to notice that it's going to create a complete new folder called components UI and there's going to be the code for the button that's why shaten is so cool it doesn't add any code you don't need need it simply adds a button component we just installed and you can modify its source code it's not like we'll need to do that but you can if you want to so with that said now we have everything set up and let's try to use that button within our signup form the only thing you need to do to do that is import button from component UI button and then use it so back in our app let's do just that import button we're going to copy this button and just use it right here within this div let's press save and back in our application if you go to for slash sign-up which is the route for our signup page you can see the O layout that's correct and the reason for that is that our o layout it's not returning any pages that are within it so to be able to see this button let's first focus on implementing the O layout the only thing we'll need in here are two special components from react router Dom so let's import a component called Outlet interesting name I'm going to soon let you know what it does and then navigate and we can import that from react router Dom now later on we'll have to figure out if a user is authenticated so for now we can simply say is authenticated is equal to let's do fals for now later on this is going to be a dynamic value based off this Boolean variable we can return a react fragment but then we can open a new Dynamic block of code and say if is authenticated in that case if we are authenticated we can return a navigate to forward slash so we want to navigate the user to the home but if we're not authenticated in that case we can return a react fragment like this that's going to have a section within it and that section is going to render the outlet meaning what has to be on the page we're on such as sign up or sign in whatever is Within These pages right here great so now let's save this go back to our app and you can see a wonderful click me button great now let's go back to the normal size and let's actually start implementing what we can see here on the finished website a complete sign up and sign-in pages with the design and the forms to do that we can first style the layout a bit by giving this section A Class name equal to flex Flex D1 justify Dash Center so we need to ensure that the form is centered horizontally as well as items Das Center which is going to center it vertically it's going to be one below another so flex-all and padding y of 10 meaning padding on top and bottom this is going to now Center it but on the right side of the screen we want to show this beautiful image so to do that we can render a self-closing image tag that's going to have a source off and now how are we going to get access to this image I created a few wonderful assets that I want you to be able to use so so down in the description in that same GitHub gist folder where the code is you'll be able to find a link to a zipped public folder download it unzip it delete the existing public folder and then simply paste the new one right here not within the source like I did it happens you have to put it right here outside of everything so it appears on top of the source folder and once you have it there you'll be able to see the assets that contain icons and images which means that we can Define our path right here it's going to be for/ assets slash images slide-img do SVG the alt is going to be logo and class name is going to be hidden so usually on mobile devices it will be hidden but on extra large devices it will be showing so it's a block we wanted to take the full height of the screen so h- screen the width is going to be 1/2 so 1/ two it's going to be object cover and BG no repeat great so now that we have modified our o layout we can close it and if we go back to our website it's going to look like this pretty cool right we have the right side which is the image and then we have the button on the left side which right now doesn't do absolutely anything but soon enough it will that's because we'll create a comprehensive sign up and sign-in form and we'll do that using shaten most comprehensive and most complex component and that is the form so go here and search for the form it is the most comprehensive one because forms are tricky they're one of the most common things you'll build in web applications but also one of the most complex so that's why shaten automatically out of the bot uses react hook form which is a great library for managing forms and states and then Zod which is great for form validation here we can learn a bit more about the anatomy of a form so you have a form component and then you have form Fields within it each form field has a control a name and then you can choose how it's going to look like it's going to render an item a label form control description and a message and here we have a complete form example so let's go ahead and follow the steps to create our form first we need to copy the command to install it so we can go back go to our second terminal and paste the command to add the form soon enough it will be done and then we can actually use it so first we have to define the shape of our form by using a Zod schema of course you can learn more about Zod in the official Zod documentation but don't worry it's a pretty simple IDE library to use and I'm going to teach you how to use it so let's copy import everything as Z from Zod and then const form schema we can paste that right here at the top we can put this import on top as it is external import and we're going to put this right here because it is coming right here from our code and this form schema is going to go right here within our component the next thing they say we have to do is Define a form by using the use form hook coming from the react hook form Library so let's go ahead and import import Zod resolver as well as Z from Zod as well as the form schema which in this case can be placed above the component but then we'll also need to import the form and everything else that is in here so instead of copying everything let's copy just the things that we need first I'm going to copy the Zod resolver paste it right here at the top and then I'm going to copy the entire form right here or rather just the definition of a form and we can paste it right here on top and the form schema can go outside right here so now we're defining our form we're also using the form and this has to be imported from react hook form the use form right here but now that we have defined it we can actually build out our form so we need to import all of the different components that go into building a form which we can paste right here on top and you can notice that one of these is an input which is another component we have to install because if you check the component so far you can notice the form label and button but no input so to install the input you know what we need to do just say MPX CH C Nui latest add input it is as simple as that we can also put all of these components in one line so it's easier to see everything just like so and then we can actually build build out our form by copying the form right here and let's paste it instead of this button we can indent it properly and save it and that's it you now have a fully accessible form that is type safe with client side validation and let's see if it actually looks like this and would you look at that it looks amazing but it's only one input and one button but the validation is working wonderfully and chatan has this beautiful button minimalistic UI so now let's convert this into this and make it fully functional to do that we won't simply keep everything in a single file as that would quickly clutter our view and wouldn't be so reusable so we're going to use many reusable practices to turn this into a component that we can then reuse and manage its data more efficiently and the first step we'll do to achieve that is we're going to extract this form schema into a separate vol validations file so let's go ahead and go to file explorer collapse everything and go within Source within lib and then right here create a new folder called validation within it we can create a new index.ts file and within index we can do something similar to what we have done in the signup form we can import everything as Z from Zod and then we can create Define a form schema so right here let's define it but in this file we're going to keep many different form schemas so we have to Define which one is it this is going to be a signup validation schema and we're not going to Define it in this file and then not use it we have to say export const sign up validation to be able to use it so now we can go back to our signup form and we can import form schema or rather we can rename it to signup validation coming from atli SLV validation and we can use it in three places where we used it before and in this case we also need a z from Zod as we're referencing it right here as a type great so now we have just extracted one thing but instead of Simply extracting That Base example we had let's actually make it a bit more meaningful we're not just going to have a username we're going to have a name as well well so let's define it at the top let's say name is going to be a z. string with a minimum of two characters and then as the second parameter of a specific option you can provide the error message so in this case we can say a message is something like to short there we go and then you can continue doing that we have the username username is going to also be a minimum of two characters we don't need a maximum here and we can also provide a message of something like too short then we can have an email which is going to be a z. string. email like so and then we can have a password which is going to be z. string and it's going to be a men of eight characters and we're going to say to short if it's less than eight of course feel free to provide more meaningful error messages something like password must be at least eight characters you can do that for all the other ones now we have our proper signup validation but as you can notice we're using it here but as for the default values we're simply defining the username so let's also add a name at the start equal to an empty string let's also do a username after that we're going to have an email and finally we're going to have a password so now we're starting to create the structure for what our form is yet to become and of course the next thing we have to do is actually create our form with all of the necessary form Fields so if we go back to the finished site right now we still have just the input but let's go ahead and put this side by side with our editor so we can see the changes that we make live now we have our form on the right side and the code on the left so let's go ahead and turn this into an actual final form to look exactly like this one does to be able to do that we can start with the outer div or rather with the form we don't need to wrap the form with anything as the form is going to be the most outer side container so we can remove this outer div and we can select everything within the form just like so and indent it properly I always try to keep my code clean now within the this form we're going to have a div so right here create a new div and this div is going to have a class name equal to on small devices width is going to be 420 it's going to be Flex Center and it's going to be Flex C so the elements appear one below another next we have to create this logo on the top so let's immediately do that here we can render a self-closing image that's going to have a source of / assets SL images SL logo.svg and you can give it an ALT tag of logo now if you save it you should be able to see a nice looking logo appear right on top as soon as you reload and there we go you can see logo's icon actually the entire logo is there as you can see when I drag and drop it here but you cannot see it as the background is white so let's go ahead and figure out why our background is not dark as it was dark before if you head to your global. CSS file you'll notice it got overwritten by shaten and it's no longer applying the black background on our body so once again to get back to our previous globals you'll have to go to the GitHub jiz down below copy it and then paste it right over here once you do that you're going to get an error because our tail wi. config.js also got overridden so copy it from the GitHub gist and then paste it right here that's going to ensure that you have access to all the necessary theme colors and everything is going to work as it should now with the dark mode so below this image let's create an H2 that's going to say something like create a new account and we can give it a class name of H3 bold now I know what you're thinking why H3 if the element is H2 well that's because on medium devices is it's going to be H2 bold so we're going to make it a bit smaller there we can also give it a padding top of five so PT of five and then small devices a larger PT of 12 to create some spacing below the H2 we can have a P tag and this P tag is going to say to use snapgram enter your account details and now we can give it a class name that's going to say text- light-3 small- medium for the font size on medium devices base Dash regular and a margin top of 12 and we don't necessarily have to say count just details to use a bit less width now we want to wrap our entire form within this div so let's copy the ending tag and paste it right here below the end of the form and let's expand our form to fit nicely right here there we go now our form is going to have a class name of flex flex-all gap of five w- full and then margin top of four this is going to make the elements extend the full width of the screen or rather full width of the container so now everything looks uniform the first field we have is going to be a name field we can change the form label to name and we can remove the placeholder but rather we can give it a type is equal to text and a class name equal to Shad input if we save this it's going to get this beautiful view and we don't need a form description I believe a title or rather a label is enough so now we're getting closer to this final view so let's go ahead and duplicate this form field right here below and the second one is going to say username and we can change it to username here as well that's great two done two more to go let's duplicate it two more times the next one is going to say email and we can say email here as well as change the type of the field to email there we go and the last one is going to of course be the password so let's change this to password type password as well and say password here so now once we type here it's actually going to be dots meaning it's hidden and finally we need a beautiful button that's going to allow us to submit the form so let's give this button type submit a class name equal to Shad dasb button undor primary there we go but it's not always going to say submit sometimes it has to load meaning we've submitted it and it's doing its action so what we can do is create for now a fake field called is loading so const is loading is at the start going to be set to true and now if we go back we can use that property to make some Dynamic changes if is loading in that case we can return a div that's going to have a class name equal to flex Center and a gap of two between the center and the flex you need to have a dash and here we can say loading dot dot dot else we're going to render something else which is simply a text that's going to say sign up and there we go now we can see loading but to make this loading a bit more interesting let's create a new component called loader so we can go to our components and create a new folder within there called shared these are components that are shared all across our application within it we can create a new loader. TSX and run rafc within here we can wrap everything in a div that div is going to have a class name equal to flex Center and w-o and within it we can render just one self-closing image with a source equal to SL assets SL ions SL loader. SVG we can have an ALT tag of loader we can have have a width of about 24 and a height of 24 now if we go back to our signup form we can call our self closing loader right here by putting it here and then double clicking and pressing control or command space to import it from components if you save it you can see this loader appear right here which is amazing now of course we're not submitting yet so what we can do is bring this is loading to false because we haven't haven't yet submitted we have nothing to load and now we have our beautiful form that you can see right here it is a bit wider and that's because we here have more words to use snapgram please enter your details let's see what do we have here to use snapgram okay let's be nice and say please enter your details which is going to make her form a bit wider great and now that we have all of those fields we have to figure out how to actually submit them but before that we're missing just one additional piece of information which is the link to go to the login as well in case we already have an account so right here below this button we can create a P tag that's going to have a class name equal to text- small- regular text- light-2 and text- center and margin top of two so that's going to provide this nice centered text we can say already have an account and if that is the case we can render a link component this link has to be imported from we don't have it here but it should be coming from react router Dom so right here at the top we can say import link from react router Dom and now if we go down this is looking good and what is this link going to say well well it's going to point to forward SL sign in it's going to have a class name of text- primary and it's going to say log in there we go let's style it a bit further by giving it a text primary 500 which is the shade of the color text- small- semi bold and finally a margin left of one so now it's looking great and it's going to redirect us to the sign in in form which doesn't exist yet we're going to create it as soon as we implement the functionality to actually log our users in that's definitely the first thing we have to do right so how is that going to work well everything starts with a button that has a type of submit and once we submit it it's going to submit the entire form right here that form is going to call the handle submit function which we have here and then the only question is what do we want to do on submit and the simple answer is we want to create the user and that usually looks something like this we say const new user is equal to a wait why a wait because usually creating a user takes some time it is an asynchronous action in the database which means we have to specify this as an async function and then usually the function to create a user is called create user account to which we want to pass the values but as you can see we don't yet have the create user account function so let's comment this out and we have no idea where is this event coming from how are we going to create our user and thankfully for us this is where aight comes in they're going to help us with databases functions storage but in this case o as we actually have to create our users and as I've told you at the start we'll be using ID's Cloud platform click the special ight Cloud Link in the description that's going to allow you to sign in and follow along with this video seamlessly and then sign in or sign up I recommend with GitHub and once you're in you'll be able to create your first project let's do something like jmore snapgram of course this is now going to be taken by me but whatever name you decide to take definitely append JSM in front of it and then click create there we go our JSM snapgram has been created and here we have our getting started guide but thankfully you won't have to follow it because you're watching this video and I'm going to teach you everything step by step to utilize all of the primary upright Cloud features we'll be dealing with OD really soon to create our users databases functions and even storage so for now the only thing you have to do is copy this ID that you've been given for your project once you do that we can go back to our application and then we can go to our Explorer collapse everything so it's easier to see as a matter of fact we can close all the files at the moment and then go to Source lib and within the lib we're going to create a new folder called aight within aight we're going to create a new file called config.sys so open up your terminal and run mpm install ight and that's the only dependency you have to install to make this work and just to verify in my case I'm on version 13.0.0.0.0 able to define a couple of things first of all your project ID and I think you already know it right it's the ID we copied from aite but we never want to share any IDs or keys or Secrets publicly so for that we're going to use environment variables so let's go to our app and then outside of the source we can create a new env. local file and within it we can Define the V uncore aprite uncore projector ID is equal to this same ID that we copied that way instead of just simply using plain text here we'll be able to say import. meta env. vorea rightor projector ID and that way it's going to be safe now here you can notice that our typescript is complaining a bit saying that EnV does not exist on typ type import meta and we just have to let typescript know that we're using V and that this is actually going to exist and the way you do that is in the source you can add a new v- env. D.S file and there you can type reference types is equal to v/ client and then close it like so and add three dashes at the front once you do that you can see that it's no longer complaining but now we can still see some warnings that these variables are not utilized so how do we utilize all of these great appes functionalities well we can say export const client for example is equal to new client so we just have to create an instance of this client and we're going to repeat this procedure for everything else so here we can say account is going to be equal to account then we have something like databases is equal to new databases then we have storage is equal to new storage and we also have avatars is equal to new avatars you can see that it's complaining for a lot of these saying that the argument client was not provided so for all of these to work we have to pass in the client within them right here so they know what they're referring to and with that said we no longer have any warnings but now we have to configure our client and we can do that by saying client dot set project it's pretty simple right it's aight config do pro ID we already have that but there's another thing we have to do and that is set up the endpoint so we can say client. set endpoint and that's going to be aite config do URL but hey how do we get this URL it's obvious it has to go here right and we can import it from envs by saying import. meta env. Vore aprite URL so now we have to go to our env. local and we have to add the Vore aprite URL is equal to a string but hey where do we get this aight URL we didn't see it here in the quick start docs it's going to say right here that we can set up endpoint as the https cloud. aight. V1 so let's copy this and paste it right here so one more time that's https col cloud. aight. slv1 and now we are properly configuring our client and this is all that we need to get started with authentication so now alongside config within aite we're going to create a new file called called api. TS and within it we can export async function create user account that's going to get in the user that's going to accept the user as a parameter and then it'll try to do something do you get where we're going with this this is the function we're about to call from within our form so now we can connect to app right authentication functionalities to actually create this user so to do that let's first follow the proper tab script Rules by defining the interface for this user and we can do that by saying that the user is of a type or rather of the interface I as an interface new user and we can Define that within a new folder that's in the source folder called types within types we can have a new index.ts and in the GitHub J down below you'll be able to find this entire file that's going to contain a couple of of different interfaces we can go through each one of these as we're referencing it in the code such as in this case export type I new user which has a name email username and password and now we can just import it right here from add/ types and now we know exactly what this user is all about once we know that we can open up a new try and catch Block in the error we can simply consol log the error and we might as well return it so return error but the better question is what are we going to do within the tri block and here we have to create a new account by saying con new account is equal to await account. create and we need to pass a couple of attributes the first one is the ID of course we can just randomly type it but upright provides us with a great utility function called ID so we can simply import ID from aight and then what you can do is just call it and say id. unique and that's it it's always going to provide you with the unique ID and then we provide the user. email user. password and user.name and for now we can return the new account so now you can also notice this account we're calling is not defined so let's double click it and would you look at that we are already exporting it from the config and if you go into the config remember that this is the account utility that we have established before by passing the client into it and referencing the account from aite that's going to allow us to deal with the O functionalities of aight Cloud so now we can close all of this and go back to our form within o forms sign up form and here we're back to calling the function that's going to create a new user so let's go ahead and uncommented double click and then press control space and import it from lib upright API and we're now hoping that we're going to get a new user right here or at least a new account back after the creation is done so let's go ahead and conso log that user right here by saying consol log new user now if we save this we are ready to submit our form by entering a name let's do Adrien we can do JavaScript Mastery and an email off contact JS mastery. proo and finally a password so let's go ahead and click sign up and we have really good validation here I'm glad we were able to see it we need eight characters so I'm going to enter them and then click sign up now it seems like nothing has happened but let's go ahead and go to inspect and then right here we can check the console we indeed did get back an object that says created ad updated ad email name password update and all this good stuff which means that this is coming back from aite which then means that our user was indeed created it's that we just didn't do anything with it which is going to be our next goal so now if we go back to our ight project and reload the page you should be able to see that a new user has been created and you can even dive into it see more information about it verify it check the membership or do a lot more stuff which is pretty amazing that we're able to set up authentication this early in the project but it's not going to be enough just to create our users we'll also have to set up our databases and our storage buckets for all of this to work because our users will create posts and we need to be able to create relations between users posts and more first we're going to create a new bucket for our media this is where we're going to upload our images so let's create a new bucket and call it media there we go as simple as it gets immediately we're given the media ID so let's go ahead and copy it and back within our app we can go to our EnV file and then we can paste it right here but before say Vore upright underscore storage uncore ID and then set this equal to this string that we got from here this is our storage bucket now while we're here let's go ahead and set up our databases as well so click create database and enter the new database name called snapcam you don't have to enter database ID because it will be generated automatically so just click create now that we have our database we can go ahead and copy its ID so go back and and this time say Vore aite _ database _ ID and we can paste it right here so now we have the aight URL and then three different IDs from three different services that aight Cloud offers now while we're here we also need to Define how our database is going to look like so the entire database structure so bear with me let's define all of the collections and relations between them that we're going to have in our app it's going to take some time to Define them but after that we'll be good to go for the entirety of this phenomenal build so let's just click create collection let's enter our first collection name which is going to be posts and click create then you need to go to settings you need to head down to permissions and you can allow access from anywhere by clicking any then check all the texts and click update so it's pretty cool how we have a robust permissions SL roll system built into aight Cloud next we can repeat the same process for our users collection so let's create a new collection called users click create go to settings same thing here we need to add permissions click any and then take all the boxes and click update and now there's going to be a third one which is going to be called saves and this is going to be for all the saved posts within here we can also go to settings go to permissions add any and then select all the boxes and click update and now we have to start creating relations so let's go to the posts collection and again make sure to follow exactly what I do here because our app is not going to work if we don't properly set up our relations it's important that we create relations immediately so everything works later on so go to attributes and then click create attribute in this case we're immediately diving to a complex attribute of a type relationship in this case we want to create a two-way relationship and this is going to be a relationship between a post and a user so we can say users attribute key is going to be creator and then the attribute key in the related collection is going to be posts and a relation is going to be many to one so this is how it's going to look like one Creator can have multiple posts and while we're here it wouldn't be such a bad idea to start sketching things out right in our ultimate nextjs 13 course we were doing a lot of sketching because we covered a tough project where we have to deeply explain all of the concept covered and this often includes a lot of sketching so in this video I want to also do the same I want to give you a bit of behind the scenes of the level of complexity we go in our Pro courses so if you haven't checked them out yet that's great this video is about react but after you watch this free video on YouTube you might want to learn nextjs server actions and all of the great stuff that it offers so add yourself a to-do after you're done with this video check out JS Mastery Pro but with that said let's start sketching the complex architecture of our snapgram application we obviously have posts saves and users so let's go ahead and create all of that as simple rectangles here we're going to have our users we're also going to have our posts and finally we're going to have our saves which are three different collections now it's obvious that we're creating a many toone relationship between our user called a Creator and our posts so this means that one user can have multiple posts so let's just create this relationship that's from both sides and we can do something like this where we're going to Simply duplicate this right here indicating that one user can have or can create two different posts so that's going to work like this and then an important thing here is is on deleting a document we must set null as this is going to set the document ID as null in all related documents meaning it doesn't exist so let's click create and it's possible that something like this happens but don't worry just go to databases select your database and then you can see your collections here specifically we're working with users and then attributes and you can see here that now we have a relationship with posts and also that same attribute should be within post as well because that's the relationship so now let's create a second attribute under posts which is also going to be a relationship attribute it's going to be a two-way relationship related to users one more time but this time not who created it rather who liked it so we're going to say likes so it's going to be likes here we're going to say liked so who liked it and then relation is going to be many to many because many users can like many different posts and then on deletion we also want to set the same set n and click create there we go and now we can slowly start thinking about which attributes are posts are going to have so right here we can make this a bit smaller and make it a bit simpler to read let's do something like an attribute which is going to be Creator we know that each Post in this case has to have a Creator and we know that a user is going to have a post attribute so let's do something like this attributes this is going to help us when creating a database or rather not because this is going to help us understand our database structure usually you would have to create all of this within your application but now aight actually creates the relationships for us which is super handy and the second attribute we have added is going to be likes so the post is going to have likes and then users are going to have liked so which posts have they liked let's move forward let's create a next attribute for our post and that's going to be a string this time the attribute key is going to be a caption the size is going to be 2200 this was a default size for an Instagram post so that's where we took it 2,200 characters default is not going to be anything and you can click create we're going to also need tags attribute so let's go ahead and create a new one of a type string that's going to be called Tags it's going to be 2200 as well and it's going to be an array of tags pretty interesting then we're going to need an image URL so let's create a new URL type yeah there's a special type for the URL which is going to be called image URL and then it's going to be required and click create we're going to also need an image ID attribute which is going to be of a type string this is needed if somebody wants to delete a post so we can say image ID of a size 2200 again feel free to choose whatever you want here and it's going to be required we need a location attribute as well of a type string so let's say location size is going to be 2200 and this is more or less it these are all the attributes that we need for our post so what we can do is instead of just typing them out we can go ahead and screenshot what we have here on Windows I usually use command shift s and then you can simply select it like this there's a similar shortcut on Mac OS as well so let's take it and let's put it right here within our fig Jam so it's really easy to understand what properties each one of our posts has there we go now we even know the type this is going to be helpful later on once we dive into the further architecture of our application now that we have all the attributes we can go to the indexes tab of our posts and this is where aite allows you to do automatic searching of your collections so click create index you can call it caption the index type is going to be full text the attribute is going to be caption and the order is going to be descending this is phenomenal essentially you have built-in search and filtering this is going to allow us to automatically search for different posts based off of caption so let's click create now we want to go to the users collection and also start creating new attributes so go to attributes you can see that we already have liked and posts let's create a new one of a type string that's going to be name we can enter the same size as before and click create we're going to also need a username for our user so let's say attribute is going to be username it's going to be 2200 and we can click create we also need an account ID so let's create a new string of account ID of 2200 let's make it required and let's click create our user is is also going to have an email so let's select an email type call it an email make it required and click create our user can also add a bit of info about themselves so let's create a new string property called bio and here they can add their biography let's click create finally we need to create an image ID attribute of type string so that's going to be image ID of the same size and this is needed for deleting the profile images when changing the profile image let's click create we also need the image URL attribute this is going to be of a type URL so let's say image URL required and create and this is it we immediately have all of the attributes that belong to our user what we can do is also screenshot it and add it to our fig Jam there we go I'm just going to make it the same size and we can put it right here below users collection there we go it's pretty handy to know the full structure especially as the app grows and finally the saves collection is remaining so let's go back to our upright go to saves attributes and we need to create a user attribute which is going to be of a type relationship so it's going to be a two-way relationship between users where it's going to say user and it's going to say save so we need to know which user saved which post it's going to be a many toone relationship because one user can save many posts and on delete we have to select set now and let's click create and also we need to create a post attribute so we know which post was saved so we can create a new relationship and we can create a two-way relationship between posts we can call it post and save make sure you call these attributes exactly the same as I'm calling them here that's necessary for the application to work and then we can do a many to one and set now and click create so now we can copy these one more time and we can add them right here below the saves and there we go so now we can see that saves actually kind of comes in between of some of the posts so here we can make this a bit smaller and we can Define that a user can save a specific post so it's going to go something like this saves and then we can go to a specific post users can create posts but users can also save the posts that they like pretty cool right and then these are the attribute of the save so this is our current structure we'll be returning back to this fig jam and whenever we need to explain something in more detail that's exactly what I'm going to do in a visual manner if you'd like me to add more visuals to our videos just let me know for now I've been only doing this in our Pro courses because we have so much more time to cover things in depth in videos the time is limited but still I'll try to make them as detailed as possible finally now that we've created our collections our database is ready this took some time but I mean it's pretty crazy really soon we now have a complete authentication system where we can add users not only that but now we can add them to our database as well in the database we have our collections with complete attributes so we know the structure of each one of our Elements which we can see right here and then we also have relationships between them and we also have storage so we can upload images to our application I mean ight Cloud really does everything you wanted to do in this case now the last thing we need to do is go to database and then copy the IDS right here of these collections so let's copy the saves go back here and we can say something like vorea right uncore saves uncore collection uncore ID it's a long name I know but it's better to be safe than sorry and finally we can duplicate this two more times we're going to save saves collection ID we're going to have post collection ID and we're going to have a user collection ID as well so for the Post we can copy it right here don't mistakenly do the wrong one and finally we can do the users there we go so now we have the ight URL the project ID the database ID storage ID user collection ID post collection ID and the saves ID in case you didn't copy the project ID before it's right here within the overview database is right here storage is right here here everything is so easy to find now we can make use of these variables by going back not to our signup form but rather to our config right here we're initializing all of these Services here but we're not yet properly setting them up and we can do that by having the URL the project ID we also need a database ID which is going to be import. meta env. vorea _ database ID we also need to get a storage ID which is going to be import. meta env. vorea rightor storage ID we also have to have all the collections so we can say user collection ID is import. meta do. vorea rightor user collection ID post collection ID is going to be import. meta env. Vore aight _ postore collection _ ID and finally saves collection ID which is going to be importa env. Vore aprite uncore saves uncore collection uncore ID and with that we have everything we need to start utilizing these services that aright provides out of the box so back in our code we can exit our EnV local we can exit our config as well and before we go into our signup form and finalize what this function does on the front end let's go ahead and implement it on the back end or rather let's utilize all of these services that aite provides so I'm going to add aight right here to the top and and I'm going to pin it this is a cool Chrome feature you can have something pinned now with that done let's go ahead and go into the aite API and so far we have only created an account which then added it right here to our a but that's not enough our user has to have relations to the post it creates which means that we need to have it in our database so right now within our database we don't yet have a user so that's going to be our next goal to add a user to our off but also to create the user's document in the database so how are we going to do it well let me show you we can go right here below create account and we can check if we get anything back from it and if we don't so if there's no new account in that case we want to throw a new error we can do it just like so throw error then moving down we can create a new Avatar URL by saying const Avatar URL is equal to avatars do get initials now where are we getting these avatars from well that's something we have to import from aight so you can double click it press control space and then import from that/ config if you remember this is going to be one of these services that aight provides account databases storage avatars and client so now we're we're using avatar. get initials and we want to get the initials from user.name once we have the Avatar URL we can create a new user but this time not a new account rather a complete new user in the database by saying a wait save user to DB just like so but the main question is where is this function coming from and the answer is it's a function that we are going to Define our cells so right below this function create new user we can create a new function export async function save user to DB this function is going to accept the user as a parameter and we can immediately destructure some of the values from that user and then open up a new function block we can destructure the account ID which is going to be of a type string we can destructure the email which is going to be of a type string as well we can destructure the name of a type string we can destructure the image URL of a type URL and we can destructure the username which is going to be optional and it's going to be of a type string as well and how do we know we're getting this well we can pass it right here when we call that function we can pass an object that's going to have all of these properties an account ID equal to new account and then dot dollar sign ID that's how app write stores IDs we can pass a name equal to new account. name we can pass an email equal to new account. email we can pass a username equal to new account. username or rather this username is not going to be within a new account because we're not passing it initially but we are passing it right here when saving the user in the database and that's coming from our form we have a field here called username so instead we're going to say user. username and finally we need to pass the image URL of a type Avatar URL which we're also passing above now we have this new user which is equal to the function call of our save user to DB and then instead of returning a new account we can return a new user which means that our create user account function is now done but of course it's dependent on the save user to DB function so let's collapse this and let's focus on the save user to DB remember above we're only using the O functionalities where we're doing authentication but now we want to save it so for the first time in this app we're going to save a document to app right database let's open up a new try and catch Block in the error we can simply console.log the error in the try we can say const new user is equal to await databases. create document one more time where is databases coming from try to think about it it's coming fromc config because we're utilizing what we configured not that long ago and now we have to pass what want to create so we're going to pass the ight config do database ID we need to know which database are we modifying then we need to pass the upright config do user collection ID to know which collection are we modifying we need to pass the id. unique and we need to pass the actual user object now you're going to notice it's going to start complaining about the app right config which we have to import from config that's exactly why we're exporting it in the first place and then we simply can return this new user and now not only are we creating the user in the authentication part which is right here but we're also creating it in the database so let's collapse it and would you look at that with two simple functions we actually have a connection to the database so what's remaining is to actually try to create our user so let's go back to our signup up form we're calling the create user account and let's figure out what we want to happen after the account gets created we surely don't simply want to consel lock the newly created user after the user is created we want to check if there is no new user means something went wrong in that case we can simply return meaning exit out of the function but we also want to play with some additional function functionality which is going to be a small toast that appears or at least we call it that way a toast that we can check by going to our Shaden documentation and then checking the toast functionality a toast is a little popup that you click and then it jumps out it can be dark like it is here but you can also have different examples where it can be light meaning something was good or a red one meaning something was really really bad so let's go ahead and implement this which is just going to provide much more intuitive workflow so we immediately know whether the user was created or not now I'm going to show you how to add this second shaten component to our workflow we just have to follow the documentation first you run the following command MPX Shad CN UI latest add toast we can do that by opening the second terminal we have here and simply pasting it once again that's MPX shaty and UI add latest add toast this is now going to add it within our components and then UI and you can see that the toast and the toaster as well as the used toast functionality were added automatically don't worry you don't have to modify these we just want to use them within our code so how do we use them well we can refer to the documentation here we need to add it to the most outer part of our application in this case it's not going to be app layout TSX it's going to be our app so let's go ahead and copy this import let's go right here to our app and let's import it right here at the top we don't need this entire part we simply need the import so we're importing it from toaster UI components and then we want to put it right here at the end near the closing main toaster like so this is going to allow us to see the toaster and then we have to use the used toast hook whenever you want to call it so right here we can import this go back to the signup form we can import it right here at the top we don't need the form description as we're not using it and then where do we want to use it we have to declare it as a hook right here at the top cons toast is equal to use toast and then we call it whenever we want it to appear in this case right here after the return so we say toast schedule description this is it but of course we want our toes to say something different so we can just give it a title no need for a description that's going to look something like this title is sign up failed please try again as simple as it gets now in this case let's be optimistic we're not going to test our application or our function failing we want to test the toast if everything works so what do we want to do we want to sign our user into a session that's the next step so we can say con session is equal to await sign in account okay and this is another function that we have to call that will soon Implement for now let's comment and out and let me tell you about something more important in this course you'll also learn how to use react query recently renamed to 10stack query as they started supporting view spelt solid and more but in our hearts it's still called react query it's going to allow us to do a lot of things right out of the box it's going to be simple and familiar but more importantly it will allow us to Cache the data we're fetching from the server it also has Auto ref fetching server side rendering support pation out of the box mutations meaning changes to the server data infinite scrolling which we're going to use and Implement in this video and there are so many more reasons to use react query in your react applications and in this video I'll teach you how to use it from scratch so what do we need to do to get started with react query and using it alongside aite well we can go right here to our lib and then next to aight we can also add a new folder called react D query within here we can create a new file called queries and mutations. TS within here we're going to import a couple of things we'll use from react query but of course first we have to install it so that's going to be at 10stack SL react dqu so let's copy this open up our terminal and say mpm install at tanack SL react query press enter and soon enough it will be installed it's a pretty lightweight Library once it's installed we're going to import use Query and queries are for fetching the data use mutation mutations are for modifying the data use Query client as well as use infinite query these are all the things we'll use from react query and once again the reason why we're using it is to simplify data fetching and mutation while getting all the benefits such as caching infinite scroll and more out of the box now what you want to do here is you want to export our first mutation so we can say export const use create user account mutation it's a long name I know but we try to make them as meaningful as possible it's an arrow function that returns a call to use mutation that then gets an object in and then we want to pass the mutation function so what are we actually doing and in this case it's going to be an arrow function that's going to return a call to our create user account function that we have created not that long ago within upright SL API and it's going to get the user right here as its first and only parameter and that user is coming right here through the function which is going to be of a type I new user which we can import from types so essentially what we've done is we've initialized a new mutation function so that now react query also knows what we are doing now we can use this use create user account mutation within our signup form and you might have seen this right here I was testing that but let's create it from scratch right here at the top we can do it even above the form we can say const get something an object out of it and call a use create user account mutation just like so as a hook we can immediately import it from addlib SL react query forqueries and mutations there we go and now what do we get back well we get back mutate a sync as well as is loading the mutate async if I can spell it properly is the actual function that we're calling right here in this case it is the create user account function that we have created not that long ago that creates the user in the authentication and also saves the user in the database so now we're calling that as a hook and it's giving us this mutate async function but we can rename it so we know what it means this is going to create a new user account so we can say create user account so this syntax simply renames this mutate function into create user account and we can also rename is loading to is creating user so it makes more sense and we no longer need this fake is loading right here so we can remove it and we can immediately use is creating user right here at the bottom there we go that's our new is loading so react query provides this out of the box as well now right now it says is loading is not defined or does not exist but don't worry we're going to fix this soon for now it's important that we have this create user account which we can call and we no longer need to use it directly from aight because this mutation is actually calling create user account from aight for us it's kind of a level in between the app right in our front end to ensure that we have easier time fetching data on react and querying and mutating the data as well as caching it so now we have this and we're calling the create user account as we were before but now this is a mutation from react query now we can also do a session which is the sign in account which is going to be yet another mutation so let's go to our mutations right here and we can create another one just by duplicating this one below we can call it use sign in account mutation so use sign in account and now that I think about it we don't have to add mutation at the end of every single one so we can simply fix this right here and modify it right here at the top as well as in the import so now if we go back we have the use signin account and here what we want to do is have a mutation function that's going to get the user but in this case the user is going to be just the email of a type string as well as a password of a type string we can put this in a new line so it makes a bit more sense and now of course we're not going to call the same function once again which is the create user account in this case we're going to call a sign in account and we want to pass the user and this sign in account will create in aide so let's go to aite API we now have create user account save user to DB but right below it we're going to export async function sign in account that's going to get the user which is going to have a email of a type string as well as a password of a type string as well and then it's going to have a try and catch block here we can simply kolck the error and in the try we can create a new email session by saying cons session is equal to await account. create session and again this is another utility provided to us by aight it's create email session to which we have to pass user. email as well as the password by saying user. password and then we can return this session so once again we have created an App function that's then getting utilized by react query and we can import it right here from aight API so now this one is for creating the user and this one is for signing into the account and now we can repeat this with the other hook that we have right here in our signup form we can say const we get a mutate async which is going to be equal to a function of sign in account and we get is loading which is equal to is signing in and once we get that we can say that's equal to use sign in account which we have to import from react query queries and mutations and now we can use this function right here await sign in account to which we have to pass the email which is going to be values. mail right here and then password which is going to be values. password and all of this is coming from our form once we have that we can check if session exists by saying if no session we want to return a new toast saying sign in failed please try again and bear with me I know this is taking some time but authentication and creating user accounts is one of the most complicated parts of every single application now after we have the session we have to store that session in our react context at all times we need to know that we have a logged in user so for that reason we can create a new folder right here within the source which is going to be called context within the context we can create a new file called oth context. TSX there we can run RFC and we'll need to import some utilities for creating context from react such as create context use context use use effect as well as use State now we need to Define how an empty user is going to look like so we can say export const initial uncore user is equal to an object where the ID is equal to an empty string name is equal to an empty string username is equal to an empty string email is again an empty string as well image URL is an empty string and and a bio is also an empty string so everything is empty after that we have to declare the initial of state so we can say initial undor state is equal to an object where the user is equal to the initial user is loading is set to false is authenticated is by default set to false and then we're going to also have the function to set the authenticated user so set user is equal to a function set is authenticated this is for setting up a Boolean value which is also going to be a function and then we're going to have a check off user which is going to be an async function that's going to return either a false or a true which is a Boolean value just like so why we have this to know whether we have a logged in user at all times and now we can declare our context but by saying const O context is equal to create context we can Define the type of that context by providing this syntax and then referencing the I context type which is coming from addtype if you look into this this is simply declaring the types of everything we have now discussed and finally we need to set it to the initial State now instead of calling this component o context we can call it o provider because that's going to wrap our entire app and provide the access to the context every context needs to have children because it wraps the entire app and then displays whatever is within it we can also Define the type of children to be equal to a react. node and I believe it's called react node so we have to add that here so now what do we do right here within it well we want to define the state of this user so that's going to be us use State snippet called user set user as well and at the start it's going to be equal to the initial user variable that we have declared before and we can also give it a context or a type of I user which we can import from types so this is just so our typescript knows exactly how our user is going to look like we're going to also need States for loading so we can say use state is loading set is is loading so we can write here declare that and then at the start it's going to be false and we can repeat this as well for another one use state which is going to be is authenticated set is authenticated at the start set to false because we don't yet have users that are logged in what are we going to do then well we're going to wrap everything in our o context that's going to look like this of context. provider and we need to pass it the value so the value will be equal to value and we can declare what we're passing right here on the top by saying const value is equal to an object that's going to have the user the set user function which we will declare soon it's also going to have the is loading it's going to have the is authenticated it will have the set is authenticated as well and it's going to have a function called check o user which we can Define right here const check o user is equal to a function right here and now we're passing that value to our provider also we need to render the children within it right here now of course the value is going to complain because there's going to be a mismatch between the types but we'll solve that really soon once we utilize the check off user function so what is this function going to do well it's going to be an async function that's going to have a try and catch Block in the catch we can simply say console. log error and we can return a false meaning user is not authenticated we can also have a finally clause which is going to set is loading to false meaning we're done with loading but in the try we'll actually try to get to the currently logged in user account so we can say const current account is equal to await get current user and this is a function will create directly within aite so let's go to aite API that's going to be right here and let's go below the sign in account export async function get current user and we can open up a try and catch block block as we always do in the catch simply console.log the error and here we can say const current account is equal to await account. getet and then we can check if that current account doesn't exist we can simply throw a new error but if it does exist we can try to retrieve that current account by saying const current user is equal to a wait datab bases. list documents so here we need to pass the database ID from which we want to read The Collection ID from which we want to read and then the query of what we're trying to fetch so we need to get a list of all user documents in a given collection first we need to pass the aite config database ID then we need to pass the app config do user collection ID and then we need to pass what we're trying to fetch which is a query of a type array so we can say query. equal we want to get the account ID and we want to get only the current account do dollar sign ID and this query is coming from aight so we can import it at the top finally we can do another check saying if there's no current account or current user this time we're going to throw an error but if we have it we can return a current user. documents zero there we go so now we have the get current user function which we can now use within our OD context by simply importing it from lib ight API so here now we check if the current account exists in that case we want to set our user so we can say set user and then we set the ID to be equal to the current account dollar sign ID the name to be current accountname username to be equal to current account. username email to be equal to current account. email image URL to be equal to current account dot that's going to be image URL and then bio to be equal to current account. bio of course what you could have done is you could have destructured all of these values from the current account right here by using the destructuring assignment and then pasting them here you also need to add commas to the end and if you did that you can also put it all in one line as it's not taking too much space and now you don't have to mention current account every single time so it's going to look a bit cleaner like this and for other properties you don't even have to say what it is if the name is the same which in all of these cases is so you can simply keep the key name here since we no longer have access to the entire current account we can just refer to the ID and then all of this also fits in one line so we can put it in one line like so this is in my opinion a bit easier to understand what we're doing but we have to be careful and typescript comes in really handy here if I wasn't using typescript I would do it exactly like this I would destructure everything and get the values but if you read this in typescript it's going to say property dollar sign ID as well as all the other ones do not exist on type document or undefined so if you look into the get current user you can notice that here it's great it's returning all of these values but in the catch it's not returning anything so if this function fails then these values will be undefined and and they'll cause an error so in this case to make our application less error prone I would actually get back a bit and I wouldn't D structure the value although it's taking a bit more space and maybe includes a bit more words I would still keep it like this sometimes more words is not bad if your application is more robust finally if we get to here once we set our user we can also set the authenticated status to true and return true as well if we outside of this block we're going to return false and this is our check off user function now this has to be called whenever we reload our page and for that we have to use the use effect so we can define a new use effect hook that's going to have a function like so and a dependency array like this empty meaning it's only going to be called whenever the app reloads here we can look into our local storage so we can say if local storage. get item upright called it cookie foldback is triple equal to a string of an empty array or it's a local storage. getet item cookie fullback is equal to null in that case we simply want to navigate the user back to the sign-in screen so in that case we can import a new hook at the top import use navigate which is coming from react router Dom and we need to initialize it right here at the top by saying cons navigate is equal to use navigate and now we can call it navigate to SL in and I notied that I didn't close the local storage. getet item so here I'm going to close it and this is how it's supposed to look like finally whenever we reload the page we want to recall the check o user function we have created above so now we have our use effect we have our check off user we're passing all of these as values and we're wrapping our entire application with all of these values so that at any point in time we completely understand whether our user is logged in or not finally we can also export right here at the bottom export const use user context this is going to make it simple for us to call this context every time which is a function call to use context and then we pass in the O context great so now we have this phenomenal context and I notice that here it says o provider which is not really used we have to export it right here export default o provider not o context and I want to point your attention to something this is a complex app the files are also complex there's a lot of logic Happening Here and although I try to explain everything to the best of my ability it's possible that either I or maybe you miss something it's easy to make a typo right so test your application thoroughly we're going to test it together after we're done with this authentication and if something doesn't work the complete GitHub repository is going to be down in the description so simply refer to all the finished files and simply override the things you have so far to ensure that everything is good and if you're still having some errors or disc Community Link is going to be down and we have a forum specifically for this video for everybody to assist you with the problems you're having so with that said let's now utilize this odd context within our signup form right here we can say const is logged in is equal to a wait check off user which we can import from our context so right here we can say const check off user as well as well as is loading which we can rename to is user loading is equal to use user context like so and we can import it from use user context context o context there we go so now we're calling it and we're getting the Boolean value back is logged in finally what we want to do is if is logged in in that case we want to call the form. reset so we want to reset the form and we want to call that same navigate remember from react router so that's going to be link but also use navigate and we Define it right here cons navigate is equal to use navigate and now we want to navigate to the homepage because we are successfully logged in so we can say navigate to forward slash else if we're not successfully logged in we can again show a toast saying sign up failed please try again and we can immediately return it and this is our onsubmit function a lot of things were happening in the meantime we worked out our database we worked out our react query ight we did everything also we created contact in the meantime so a lot of stuff has happened let's go ahead and test it out so we can go back through application I'm sure something's going to be broken so let's go to inspect console and let's reload the page as you can see it's saying that we have an error in the signup form saying that there's no query client set use Query client provider to set one the reason why we're getting this error is because we didn't actually utilize our o nor our react query in our app with we simply wrote some code in some files but to actually utilize it we have to go way back to our source main. TSX and we have to wrap our app with all of these providers so first let's wrap it with the O provider which is coming fromc context o context and then we can put our app right here within it and indented properly this is the context we have created but with react query we also have to create our own context so let's go into lib react query and create a query provider. DSX here we have to do something similar we've done with our own context by running rafc instead of a default export we can simply use a named one export const query provider we also get the children right here because we need to show the entire app within it which is going to be of a type children react. react node like so we can also just import react node at the top that's going to be a bit simpler so we can destructure react node from react and now it's going to fit in one line and then we need to return query client provider like this that we can import from t stack react query it's going to have a client property equal to query client which is once again coming from T stack react query so we can import it at the top and I believe it should start with a lowercase letter so it's a query client like so and it's complaining right here that's because we have to set up a new instance of that query client by saying const query client with a lowercase Q is equal to new new query client that we call like this and then we pass the lowercase one right here and finally we can render the children right here this is similar to our own context we have created before so now going back to our main alongside wrapping it in the O provider we can also wrap it in the query provider which is coming from lib react query query provider and we can put all of this within it and in then it properly so now we're properly wrapping our app with everything we need and we can again check the errors now the error is saying that is creating user is not defined add signup form so let's go to our signup form and let's search for is creating user that is creating user is coming right here from our use create user account so why would this is loading not be there if it's actually saying that it's not returning the is loading property well this is coming from use create user account and that is a mutation from react query so let's go ahead and check out our package Json and would you look at that tanac just recently changed its version to version 5.0.0 and When developing these projects for JSM they take a couple of weeks up to a couple of months to create so it's possible that our development version is using an older version of react query this is actually quite exciting for you right now because we're going to do some live debugging we're going to go over the documentation of the new version and I'm going to show you how you would deal with this error if you're following a video and something got outdated so the first thing you have to do is go to the library we're using and then go to the docs in this this case we're wondering about the loading so if I search for is loading no nothing is here but if I search for just loading itself we can see displaying Global background fetching loading State maybe that's useful now we can see that this is for Global fetching right but we want to see maybe use is fetching no let's see if I can find anything useful now no this is not that useful let's see a quick start here we can use the use mutation they are creating everything we discussed in this video creating a new query client using that query client and using one mutation exactly as we are but in this case I don't see there're using the loading so let's go a bit more in depth into the overview and there we go here the user query and it indeed is using the is loading property but this is a query and not a mutation we have to differentiate the query from a mutation mutation so maybe we want to read a bit more about the mutation so let's go into mutations and let's see how that works so we can use a mutation and apparently there is a mutation that is loading also the is error and is Success so let's compare the two con mutation is equal to use mutation and they use it directly right here within the code oh this is interesting so unlike queries mutations are typically used to create update delete data or perform side effects for this purpose stack query exports a used mutation hook but I just figured out I'm reading the V4 docs we want to redirect to the latest version oh there we go can you see the difference mutation that is pending and not is loading okay okay I get it maybe they wanted to make a change from the query so in the query right here once we try to call it yeah they're also calling it is pending so kind of waiting for something not loading but pending right okay okay I'm going to give it to them but now if we go back to our application and go back here and simply use is pending instead of is loading you can see it actually works this is amazing so now if I save the file and reload the page everything seems good but it's saying is creating user is not defined I think we called it is creating account so let's simply copy is creating account move all the way down and then modify it and now we're back to our sign in form which means we were redirected let's try to close and reload okay no errors that's good but let's go back to the sign up form that's what we were working on this entire time okay this is interesting so every time we go back to sign up it redirects us back to sign in I'm guessing that's because it thinks we have already created a user so what we can do is just go back here go to the application Tab and check our local storage it seems to be empty as well as the session storage so the question is why are we getting redirected the only place where this could occur is the place that happens as soon as we load the page do you know such place I think that's going to be our odd context here we have a use effect and here we navigate to sign in so right in here for now we're going to comment out this second line and we can put it right here above and save it and remove this or sign if we do this and now if we go to sign up you can see it's no longer going to redirect us everything is working and there we go go we can finally see our signup screen we've been working on for such a long time but if you think about it we weren't working on just the signup screen we were working on everything else we'll need for the entirety of our application so now if we go back to our signup form we know what needs to happen after we successfully create an account we're going to create a session add that to the user context and then navigate to the homepage so let's see if that works let's try with something like the real JSM we can also do that right here the real JSM the email can be something like let's do Adrien JSM mastery. proo and we can choose a specific password and click sign up it says loading and it disappeared or no it didn't it actually redirected us to the homepage which right now is completely empty empty and has the root layout after all this hard work we should have implemented that confetti screen to also pop up as this was stuff what we've gotten here if something didn't work for you definitely make sure to refer to the codebase what's also possible is that while you were trying to log in maybe you use the same email before so your user already got created if that's the case try a couple of different emails and usernames and ensure that isn't the case but now that we have successfully created our user you can see that we have it right here under a user collection no longer is it just under o but also under databases users and we have the real JSM with the username account ID email and everything else so this is great this means that we have just added a document in our database and also that we have logged in our user so now if we go back and reload the page you can notice that we stay here because it knows that the user is already logged in but of course to completely finalize our o we need to implement the login screen as well so what we can do is right click go to inspect go to the application tab right here and then under local storage you'll be able to see a cookie fullback this was added by ight what you need to do is just clear it this is going to clear here our existing session and then we can go back right here to OD context and we can check if local storage that get item cookie fback is null in that case want to redirect back to the sign in screen so now if we save this you can see we're redirected to the signin form so now let's try to implement the sign in trust me to do it it won't be as difficult as implementing the sign up what we can do is copy literally the entire sign up form exactly as it is and then go to sign in form and paste it right here first of all rename it from sign up form right here at the bottom to sign in form also rename it right here at the top and now there are couple of modifications we'll have to make let's start from the top to the bottom we'll be using the use user context that's okay and we'll use the use signin in this case we don't need the use create account the form is only going to accept the email and the password not the name and the username as well and we have to change this to sign in validation so let's go to our Zod which is right here under validation index DS and we can duplicate this right below rename it to sign in validation and only contain the email and the password we can remove the name and the username then you can go back and doubleclick this and press f2 this is going to open up a rename window or you can just simply press sign in and press enter it's going to automatically change all of the naming if this didn't work for you simply exchange every time that it says sign up to say sign in after that we have our submit Handler we also get the values but we can skip the user creation process and only focus on the session still the check-in is going to be the same and everything else is going to be exactly the same but we'll have to modify our form instead of create a new account we can say log in to your account we can say something more personal something like welcome back please enter your details then we don't have the first two Fields so we can completely remove them the only thing we do have is going to be the email and the password so now if you save this you can see it's no longer going to be is creating account this time it's going to be is user loading and is that it we won't need this rename right here and we won't need use create account if we save this our form is back and we also need to change the last thing that it says right here as well as the button it's going to say sign in and then here we can say don't have an account in that case you can sign up and then this is going to redirect to sign up you see how simple that was and there we go now if you click it you go to sign up you go to login this is looking great and now let's try to log in with the account we have created I'll use the same email and password and click sign in this time it doesn't seem to go through let's see why that might be the case I'm going to go to inspect and then I'm going to go to console and reload the page I'll try to enter my same email and password one more time and click sign in it almost seems like nothing is happening so our submit button is actually submitting the form we don't need this is pending right here and then we call the onsubmit Handler which should sign us right in and then if we are logged in it should navigate to forward slash but in this case for some reason it doesn't do it I'll try to reload even if I reload we're still here on square one but that's okay let's figure it out together let's see if we actually get right here so let's try to console.log is logged in and then we can say console. log navigating I'm guessing we're not getting to right here so I'm going to save it and I'll enter my details one more time and press sign in it's almost as if nothing happens we're also not getting any toasts so that's a bit suspicious let's add some more conso locks a bit higher right here let's conso loog session and let's also cons log right here at the top by saying we're in that's the whole point of coding right getting stuck and getting past these errors once again let's try it together and once again absolutely nothing happens here nor here now it seems like this onsubmit function is not actually getting cold even though we have it right here under form submit and the button should indeed submit that form as it has the type of submit so one thing I'll try to do is just restart our application so go to our terminal press contrl + C and then Y and then simply run mpm run Dev one more time it's a wild guess but sometimes who know it might make things work I'm going to make this a bit larger so we can see it a bit better let's make it so large so we can see this nice image as well I'm going to enter my email and the password and click sign sign in and once again no conso logs no errors nothing is even in the network tab right here so if you clean it and click nothing is here it seems like this form is not getting fired and I really like it when this happens it exposes me to you and it makes me think it makes me want to resolve this together with you watching this video so let's try to figure it out together let's go all the way to the top of the file and let's let's see if everything is looking good we have some imports from Hook form react router Dom then we can divide our internal Imports coming from components right here we also have some more react hook form rather this is this was react ROM this is react hook form and then we have something from lib validation this is the signup validation oh no wait this was supposed to be sign in looks like it auto imported it in the wrong way this right here was supposed to be only sign in yes because now we're talking about sign in right here and not sign up actually disallowed us from submitting the form well I guess that's its job right so I'm going to delete all of the conso logs right now and save the file there we go and hope that it was just the wrong import right here so now I'm going to expand the entire app we can can see how wonderful this signin is sign up as well it's instantaneous moving between the two and we can try to log in with the account we have previously created I'm going to enter my password and click sign in and we are on our homepage this is phenomenal I know it took some time to do this entire Au and everything else but hey we're finally in and now we can start focusing on our homepage so we can close our sign in and the sign up and we can go right here to Source root pages and then homepage or rather we'll have to do the root layout first because that we're seeing but then soon enough we'll move to the homage and the rest of the content I know it took some time but we laid out a strong foundation for everything else we're about to build so phenomenal job coming this far into the video and now the exciting stuff stuff begins let's get started with the root layout the layout is going to play a major role in turning our app from this to this where we have the sidebar on the left side the whole middle part for the post and then the top creators on the right and of course it's all fully mobile responsive so as you scroll we have this beautiful mobile UI so let's get started with the root layout by wrapping everything in a div that's going to have a class name equal to w- fold for full width and on medium devices Flex now within here we'll have a couple of components so let's go ahead and create them we can do them within the shared and we can create a new file called top bar. TSX and run R efce inside of there we can do a second one called Left sidebar. TSX and run r fce if we have a left one we're going to also have a bottom bar so let's create a bottom bar. TSX run rafc and that's everything we need so far so let's go back into our root layout and let's use all of these components so here we can put the top bar at the top and just self close it and import it by double clicking and pressing control space then we're going to have the left side bar immediately below also you need to import it then below it we're going to have a section and this section is going to have a class name equal to flex Flex D1 so it expands and then h- full for the full height and within it we want to render the outlet component this component has to be imported from react router Dom so outlet from react router Dom this is similar to what we have done before for our off layout where this Outlet actually lets us show what's going to be on the homepage later on and then below it we also want to render the Bottom bar there we go so now we have everything we need right here if you scroll all the way you'll see a bottom bar there as well so now before we start with the homepage let's start with these individual Pages such as the top bar since it's at the top this is going to be a simple section so let's turn it into a section and it's going to have a class name equal to Top Bar within it we can create a div and that div is going to have a class name equal to flex between padding y of four meaning top and bottom and padding X meaning left and right of five right here we can render a link and that link is going to point to the homepage it's also going to have a class name equal to flex Gap D3 and items Das Center because it needs to Center our image so first let's import this link from react router Dom by saying import link from react router Dom and then this image is is going to have a source equal to SL assets slimes SL logo. SVG once we save it you can see snapgram appear on top let's also give it an Al tag off logo a width of 130 pixels and a height of 325 pixels there we go now below the link still within this div we want to do another div that's going to have a class name equal to flex and a gap of four within it we can create a button and this is going to be a reusable button component of course coming from Shad CN meaning from UI button within the button we can render the image that has a source equal to for SL assets SL ions SL log out. SVG and the alt tag can be log out as well there we go you can see it on there and then we also need to have a variant equal to ghost that's an interesting one we can give it a class name equal to Shad button ghost and we can give it an onclick property so that's going to be right here on click and we simply want to call the sign out functionality now this sign out is something we also have to Define so we'll have to go to our queries that's going to be within lib react query and then queries and mutations and right here we'll have to copy the Ed sign in account duplicate it right below and call it use sign out account and we simply want to use a mutation or return a mutation that doesn't have to get any properties in but it has to call the sign out account function so we can do it just like so but of course this has to come from aight so in the aight we'll have to create a new function like we have sign in account we'll also have to have another export async function sign out account we can open up a new try and catch block consol log the error right here and then on try we can say con session is equal to await account. delete session and then we need to pass current this is so cool so this was provided to us by app right so we can delete the session and then we can return deleted session now we have this sign out account within queries and mutations we can import it from app right and we don't have to call it because it's going to be self calling function or rather just a function declaration here and then going back to the top bar we can Define that mutation we can do that by going here to the top and saying const mutate in this case it's going to sign out we're going to get the is Success variable as well and that's going to be equal to use sign out account coming from lib react query queries and mutations and now we can call the sign now on click and we can also make it a an actual function like so and call it here there we go so now we can see the log out button as well here we also want to add a use effect so we can say use effect and if we have successfully navigated so if is Success then we want to use the navigate so right here we can import const so at the top we can import use navigate from react Rd we can declare it as a function con navigate is equal to use navigate and then if is Success we can say navigate Z this is going to navigate us to the sign up or the signin screen and we also need to add the dependency array or we can check for is success and then import use effect from react so the task we can import use effect coming from react there we go finally we can also add a profile photo that we can click to go to our profile so right below the button we can add a link that's going to have a two and then we want to go to for SL profile but now how do we get the ID of the currently logged in user well thankfully we have created our context so right here at the top we can say const user is equal to use user context which we have to import from atcontext SLO context and then right here we can use dollar sign and curly braces and then say user. ID we can also give this link a class name equal to flex Center Gap 3 and write within the link we can render an image that's going to have a source equal to either user. image URL or we can use some kind of a placeholder just to be safe so that's for/ assets SL imagesprofile dplace holder. SVG if we save it we can see our huge TR soon enough we'll figure out why TR I don't think I've called myself something with t are oh I have it's the real JSM so that's why it has those initials alt is going to be profile and then class name is going to be h-8 for height w-8 and then Tailwind allows us to make it rounded really easily by saying rounded Das full and now we have our top bar you might have been wondering where is this stop bar right on the desktop we don't have it but we're immediately building this application so it works well not well so it works phenomenally on mobile devices so that's why here in Mobile this phenomenal top bar appears that's great and now we also have the log out functionality so if we click it actually redirects back and we can immediately jump back in everything is working flawlessly so far the top bar is done let's focus on the left sidebar next here is where we're going to have all of the links that we have right here to get started with the left sidebar we'll have to keep our window expanded so we can see it on the desktop mode which we can see right here I guess it's tablet as well and then we can move our code just a bit to the left there we go so let's start with creating a nav because yeah even though it's a sidebar it is a navigation bar we can give it a class name equal to left sidebar we can save it and go back and now here you can see immediately that this shifted the homepage a bit to the right within the nav let's create a div that's going to have a class name equal to flex flex-all as the elements are going to appear one on top of another and then a gap of 11 to create some space right within that div we're going to have our first link and this is going to be the same link as on mobile so we can go back to our top bar and we can copy this entire link right here and paste it in the left side bar we of course need to import Link at the top from react router Dom so we can say link and that's coming from react router Dom if we save it it's looking good but we can modify the width to 170 and the height to 36 there we go that looks a bit better for the sidebar right below it we can show our link to the profile page so let's go below the link and then create another link this link is going to point to forward slash and it's going to be as before a dynamic link to forward SL profile not this what I just typed but profile and then forward slash the user ID right and we already know where the user ID is coming from it's going to be similar as with the top bar so here we can IM immediately copy what we have because in the sidebar we'll also have to deal with the logout functionality so we might as well copy most of the things we have here on the top as well as what we have defined in the component so let's copy everything from here and paste it in the left sidebar on top just replacing the name of the component to left sidebar there we go now if we save this everything still works we have the user ID D we can give it a class name equal to flex g-3 and items Das center right within it we can show an image that's going to have a source equal to user. image URL or SL assets SL ions SL profile Das placeholder.svg there we go we have our huge the real JSM let's give it an ALT tag of profile as well as a class name equal to age-14 width of 14 as well and rounded Das full now next to this we also want to show the name of the person that's logged in because we have a bit more space than on mobile so let's create a div that's going to have a class name equal to flex flex-all so it appears one below another and here we can do a P tag that's going to have a class name equal to body- bold here we can render user.name and that's going to show the real JSM and right below we can render another P tag that's going to have a class name equal to small- regular text- light-3 and it's going to say at and then dynamically user. username if we save it now we can see this is going to work but we can remove the dollar sign there we go how cool it is that we can immediately extract all of this user information directly from the user context that's what we've been working on so hard while creating the authentication so now we can simply use it now going below we want to render the sidebar links so let's move below this link and let's create a new UL an unordered list that's going to have a class name equal to flex flex-all and a gap of six right here we might as well render all the nav links one by one by saying Link Link Link and then duplicate this many many times of course each link has to have a path it has to have some content so it's going to expand on many many lines right here instead of that what we try to do as good developers being more structured is we can create something known as constants file that's a special file and folder right here above our context still within the source so create a new folder called constants and then create a new index.ts right within it here you can Define some sidebar links just like so it's going to be an array and then we can say home anything else you want to say you can add here since this is not any logic but rather just static code what we can do is in the description Down Below in the GitHub gist you can find the complete constants index.ts file so copy it and paste it here you can notice that this is mostly Bottom bar links as well as sidebar links so what this allows us to do is just jump right into here and open up a dynamic block of code and say sidebar links. map where we get each individual link which is of a type I nav link interface nav link which we can import from at/ types and then you can open up a new function block also import sidebar links from ad SLC constants here we can simply return something known as a nav link and a nav link is a component coming from react router Dom so right right here on top we can import link as well as a nav link there we go so now going here each nav link has to have a two property so where are we going to in this case we're going to link that route because each sidebar link has a route an image URL and a label so now we can also give it a class name equal to left sidebar daslink and as a matter of fact I think we need to wrap this nav link with an Li because An Li is a list item that has to go between the uls so you can put the nav link between the Li and then the class name of left sidebar link is actually going to go to the LI since we're mapping over it we also have to give it a key equal to link. label now our nav link is going to say something right and that something is link label so if we save it now you can see all of these different labels let's style it a bit further by giving it a class name equal to flex gap of four items Das Center and padding off four there we go this gives us much more space we can also render an image right here next to the label by saying IMG we can give it a source equal to link. image URL alt is equal to link. label and we can give it a class name equal to group- hover invert D white so this is just to make the color work and there we go so now if you hover over it you cannot see it we're about to fix that but this is looking good but on the final version of our application you can see that we have a currently active link so we can do that here as well but how do we figure out on which link are we on well we have to use something known as a use location so right here from react R Dom we can also import use location which is a hook and then we can declare it right here at the top by saying const path name is equal to use location and now we can use that path name right here in the sidebar links to create a Boolean variable called is active so const is active is equal to and it's active if the path name is equal to link. route based off of this is active Boolean we can also change some Styles so in this Li we can make it Dynamic by turning it into a template string like so and then we can say if is active then also render the BG primary 500 so if we save it you can see the color changes now the last thing is also to change the color of the icon so let's change the image to be also dyamic template string and if it is active then we can call the invert white so if I now save it we have to properly spell it for this to work it seems like we have one extra brace so if we fix it there we go but if we hover it's not yet fixed so let's see what that is about let's try to properly space it out so we can better see it group hover invert white and then we have if is active then also invert white if we go here you can see that it works really nicely it inverts but in this one it doesn't that's interesting that's because we have to make this a group so this Li actually has to have a group property so it knows it's grouped with this so if we hover over this it actually applies a group hover there we go so now this is such a wonderful sidebar the last thing we're missing is the logout functionality so let's add that right here below this ul and then going one more time below the div here we want to add a button and this button is going to be only almost exactly the same as in the top bar so we can just copy this entire sign out button and then paste it here if you do that you can notice the icon appear but here we have a bit more space so we can also add the text that says log out and let's also space this correctly so we have a variant class name onclick and then we have an image and then finally below the image we can have a P tag that's going to say log out out and we can give it a class name equal to small medium and LG base medium so if we save it you can see log out and that concludes our sidebar of course now if you try clicking explore nothing's going to happen because that route doesn't yet exist so while we're here what do you say that we implement the routing so that everything we work so hard on doesn't just disappear so to do that we can now go back to our main or rather to our app right here because that's where we have the routing and we can Implement all the other private routes and trust me we're going to have quite a few so let's create a new route which is going to be a self-closing component with a path of for SL explore and it's going to render an element that's going to be called I think you can guess it explore there we go so now we want to duplicate this many many times below the second one is going to be saved meaning all the saved posts right here but we cannot now see it because we broke it and that's going to render saved then we have to have all users which is going to go to all users let's expand this just a bit then we can have create post and that's going to be create post we can also have update Das poost and we need to know the ID of the post we're updating take care of these columns right here that's going to be edit post then we're going to have a specific post details so that's going to be posts and then the ID of that post so that's going to be post details and then we have a profile so that's for/ profile slid and we can also add this special asterisk which means that everything after the profile is also going to point to that profile we can say profile and finally we're going to have the update Das profile slid where we're going to render the update profile and with that said we now have all of our routes the last thing we have to do is create those pages within the pages folder right here so let's create them one by one that's going to be starting from the top all users. TSX where we can run ource let's go to the next one that's going to be create post. TSX and again run RFC after create post we're going to have edit post. TSX where we're going to create rafc after that we're going to have explore. TSX once again run rce after that we're going to run post details. TSX run rce we're going to have our profile of course TSX and run RFC and we're going to also have our saved for saved posts. TSX and run RFC and we're going to also have the update profile. TSX and we can run R afce so now we have all of these Pages you can close them by pressing control or command W don't do that while you're in your browser move to your Visual Studio code because usually it would close your tab and then you can close all of these tabs and we can go to this index within the pages and we can export all of these components so that it's easier to import them so let's duplicate this a few times quite a few actually and then we can export explore from exlore we can also export saved we can export create post we can export profile we can export update profile we can export edit post we can export post details and we can export all users right here as well and I think we're going to use the like post as well so let's add like posts as well and we need to create the component for liked posts. TSX and run RFC now that we have created all of these Pages within app you can doubleclick each word press control or command space and it's going to automatically give you the import repeat this procedure all seven or eight times however many components we have so if you do this you can see that they're all getting imported from one line which is pretty cool that's exactly why we needed to export them whereas these components are being imported in their own individual lines so now if we save this file and reload the page page you can see the sidebar and you can see that it says explore and it says home the URL changes and what it says also changes so now we have complete routing implemented in our great application before we focus on that central part we're going to first focus on the bottom bar which is a bit weird right where do we have a bottom bar here well as with the top bar it only happens on mobile devices I mean how cool is this this is a special native mobile like Bottom bar so you can press your so you can navigate your app with your thumb how cool is that so now we're going to definitely stay in mobile view we can return back to our root layout and move to our Bottom bar as that's going to be the component we're going to implement next trust me it's not going to be that complicated we'll be able to use the majority of things we have in the left sidebar to make it happen so first of all let's create a section and that section is going to have a class name equal to bottom dasar we can import a link as well as use location coming from react router Dom and then we can initialize that path name to know on which page are we currently on so const path name is equal to use location now we can do something similar to what we've done with the sidebar so let's go into the sidebar and let's copy all of these sidebar links all the way until the end and then paste it right here in the bottom bar so essentially we are going over now the side links this time but Bottom bar links which you have to import from at SL constants in this case we don't need to provide the interface and instead of a nav link we're going to use a link now if you save this already it's looking okay but we can make it look better instead of a left sidebar link you can say Bottom bar link but in this case we don't even need an l everything is going to be in a link so simply copy the key and the class name from the LI remove it completely as well as the ending tag and then add it instead of the class name right here to the link there we go that's more like it let's put this in a new line let's remove the Bottom bar link I don't think we'll need it in this case we just want to apply a couple of class names if we are active so if the current link is active in that case we want to provide it a BG primary 500 as well as a rounded Das 10 pixels to make it just a bit rounded and then usually it has to be Flex Center so we Center the link see how it changes on the bottom we want to give it a flex call so it appears one on top of another because on mobile we have more vertical space than horizontal a gap of one to create some space a padding of two and and a transition this is going to just make it animate slowly once we hover finally we want to style the image by just giving it on active invert white and then instead of a link label let's simply create a P tag that's going to render the link label but it's going to have a class name equal to Tiny Das medium text- light-2 so if we save it this is now looking good but is it looking close to the finished version okay we're almost there the icons have to be a bit smaller so we can add a width of 16 and a height of 16 as well and now I think we're there keep in mind this automatically works as well so we can now navigate on mobile devices too this is pretty crazy and it also of course works with a sidebar this is great and I would want to focus on the homepage so bad because we've been waiting to implement this beautiful homepage for a long time but I'm sure that you're aware that we're missing something before we dive into it right and that something is create post how can we see the homepage if we don't yet have any posts so I'll have to keep you waiting a bit longer until we do the homepage we'll have to focus on create post first so let's collapse this we have a beautiful create post on mobile as well we can close this the root layout as well and we can move into create post page as soon as we have this we'll be ready to fetch those posts on the homepage and display them so first of all the layout and then the functionality of creating and finally reading those posts on the homepage once again exciting stuff coming really soon to start creating our create post page we can wrap everything inside of a div that div is going to have a class name equal to flex and then Flex one so it expands nicely let's go back to our current website and let's add another div that's inside of this existing div that's going to have a class name equal to common Das container as we're going to reuse it a couple of times within this div we can have another div and this div is going to render an image this image is going to have a source equal to for slash assets SL icons SL a-post SVG it's also going to have a width of 36 and a height of 36 and it's going to have an Al tag of ad that's because this is going to be an icon to add a post finally we can create an H2 right below it that's going to say create post there we go we can style it a bit by giving it a class name equal to H3 dasb on medium devices H2 dasb it's going to be text left as well as w- full we want to style this out div by giving it a class name equal to Max dw- 5xl so really wide width we also want to give it a flex start so now it appears as a flex container a gap of three to create some space a justify Das start and a w-o for full width and now we have our create post similar to what we have here but now as you can notice we start start with something known as a form similar to what we've done with our sign in and the sign up a form with a couple of fields a caption photos location and tags so in this case we want to create this as a new component it's going to be called a post form so let's create a new component within the components folder and then not within shared but rather within a new folder called forms finally within the form we can create a post form. TSX inside of which we can run RFC now back in our create post we can simply render the post form component and import it from components form post form there we go this now allows us to dive into this form which we're going to create as a reusable component so we can reuse it later on in many different places so how is our form going to look like well it's going to be a typical shaten form so immediately we can go back here and search for our form and then we can get our example we know how form Fields look like we know that we need to have a form schema as well and then we need to define a form Define the onsubmit and finally build out our form so let's do so step by step first we can import everything that we need from here and paste it right here at the top then we're going to define the form as well as Define the onsubmit that's going to be within the post form then we need to import everything we need to make her form happen so we can put that right here and finally we can Define the form within our application right here now if we save this and go back back you can see simple username form but instead of a simple username let's make it a bit more interesting our form is going to have a class name not of space Y8 but of flex flex-all gap of N w-o and then maxw d5xl within it we have a form field of caption it's going to be a form item with a form form label that's going to have a class name equal to Shad Das formore label and it's going to say caption instead of an input this is going to be a text area so this is another component that we have to install so let's copy it let's go to our second terminal and let's say MPX shaten UI latest add text area with a lowercase T and press enter once it is installed we can simply import it from do/ UI text area we won't be needing a form description but to our form message we can provide a class name equal to Shad Das formore message and we can also style our text area by giving it a class name equal to sh p- text area and custom- scrollbar now this is more like it we can now duplicate this form field one more time below this time it's going to say file it can say add photos right here as the form label but this time it's not going to be a text area it's going to be our own component that we'll create called file uploader so let's simply call it like this and let's define it within our components and then shared called file uploader dtsx and we can run RFC back in the post form we can import it right here save it and we can see file uploader soon we're going to make that happen as well but for now let's duplicate our form field one more time below this time it's going to to say location and it's going to render a form label that's going to say add location instead of a file uploader it's going to render a regular input that's going to have a type is equal to text and a class name equal to Shad input there we go if we save it we have a location input and finally we can duplicate this form field one more time below for the last time we're going to say tags we can say add tags and then in parentheses separated by Comma just like this so people know what they have to do we can end parentheses and then we can also render an input it's also going to be of a type text but this time we can give it a placeholder something like art expression and learn whatever right some tags that we can add there we go if we're doing a coding application it can be JS react and nextjs there we go so if we save it this looks great and finally we have to have a button so below all of these form fields we can create a new div inside of that div we can have our button and below it we're going to have another button the first button is going to be not of a type submit but of a type button it's going to have a class name equal to Shad button unor dark4 and it's going to say not submit but cancel okay so we need to be able to cancel the submit of the form let's put this in multiple lines there we go so this is one of our buttons and then the second one will be submit it's going to say submit it's going to have a class name equal to Shad button primary and wh space no wrap there we go now we can style this div that's wrapping these two buttons by giving it a class name equal to flex Gap D4 items D Center and justify Das end there we go now they're nicely aligned at the end now the majority of the UI is done but let's go ahead and focus on the file uploader that's one component that's going to be one of the most important components in our entire application we are building a snapgram and you have to snap some photos right and then upload them so let's go ahead and Implement our file uploader component to implement it we'll use a package called react drop zone that allows you to drop some things in so let's install it by running mpm install react d drop zone and while it's getting installed let's browse his docs if you Google react Drop Zone this is the first thing that's going to show up and here you can see its usage first we need to import react and use call back from react as well as use drop zone so let's do just that never reinvent the wheel always just refer to documentation when you can then we need to get a function called on drop that we can put right here there we go and then our outer div needs to include all the get root props and the input needs to include the get input props so let's copy this entire div right here there we go there are multiple ways of doing it as you can see but for now we're going to be happy with what we have at least I hope let's save it and it says drag and drop some files but we can really see where to drag and drop them so let's style this a bit further let's give this div a class name equal to flex Flex D Center flex-all BG D dark D3 and rounded d excl as well as cursor Das pointer so we know it's clickable then let's make this input a class name equal to cursor Das pointer so we know we can click it as well and then let's create a new use state for a file URL so right here at the top we can say use state which is going to be equal to use State snippet and let's call it file URL as well as set file URL at the start equal to an empty string we can also import use State coming from react right here at the top use State great so now instead of saying is drag active let's rather check for is a file URL there has it been uploaded if it has been uploaded we can return some kind of a div right here else if it hasn't we can return something else so let's create a new div let's say test two and here let's say a div that's go going to say test one we can delete everything else so now you can see test two meaning we don't yet have a file URL so now let's create this nice interface from which it's app parent that we can actually upload the files to do it we can give this div a class name equal to fileuploader dashbox and we can save it within it we can create an image that's going to have have a source equal to SL assets SL ions SL file- upload. SVG that's much better the width is going to be about 96 and the height is going to be about 77 finally we can give it an Al tag equal to file upload below it we can create a new H3 that's going to say SVG PNG JPEG and we can give it a class name that's going to be equal to text- light D4 small regular and margin bottom of six there we go now instead of making this an H3 let's make this a P tag because it's small and then Above This P tag let's create an H3 this H3 is going to say drag photo here we can give it a class name equal to base- medium as well as text- light-2 margin bottom of two and margin top of six there we go that's more like it and we can also add a button in case people want to click and not drag so we can add a button that's going to say select from computer we can then import this from UI button and give it a class name equal to Shad button undor dark4 and save it there we go this is more like it now the last thing we have to do is implement the functionality so how are we going to figure out when something gets uploaded well in this case we have the get root props and get input props we won't be needing is drag active from use Drop Zone on drop to the second parameter to this used drop zone is going to be what do we accept so we can say accept an object of image everything and we can Define that right here that's going to be an array of PNG we can also do a JPEG and we can also do a DOT jpeg like this also maybe an SVG who knows why not there we go so now we're defining what can we use but now let's define a function on drop what happens once we actually drop some files well let's also create another use state right here and this use state is going to be for the file itself so file and then set file at the start equal to an empty array because we can pass multiple files and the file URL is of course only the URL of the file we pass so what do we do once we drop it we set file to be equal to accepted files and then as props to this component we're going to pass two additional things so going back to our post form Finding where we have the file uploader we can pass two things we can pass the field change and we can also pass the media URL the field change is coming right here from the field of this form field so that's going to be field.on change but the media URL how do we know what is the URL of this media well that's going to be coming through props so right here we can say the post form is going to accept a post but this is only if we're updating it right if we're updating the post then we need to have an existing post otherwise we don't have anything so in this case if we do have a post then we can pass post question mark. image URL and now we can dive into the file uploader and accept those props so we're getting the field change as well as media URL and for now we can put these as a type any and alongside setting the file we can also set field change like this to accepted files and then we can set file URL to be equal to URL dot create object URL and then we pass in the accepted files zero so the first file that we have there and that's going to give us the URL as the Callback we want to add the file right here here we need to define the type and this type has already been defined by react drop zone so we just need to import it at the top by saying file with path and now we can say this is of a type right here file with path we can also Define these two props by saying file uploader props and then we can Define this interface or the type right above by saying type file uploader props is equal to we first have the field change which is a function that accepts files which is of a type an array of files and it doesn't return anything so void and then the media URL which is going to be of a type string great so now it's complaining a bit about these accepted files that's because here we can Define what a file is a file is an array of files so we can Define it like so and we can put it in a new line so it's easier to see what's happening there we go we have the used callback where we have accepted files and this is actually going to be an array of file width paths and then everything is good once we do that we're actually ready to set all of our states to the file that gets uploaded so let's try to upload a file I'm going to grab one from our finished application let's do this one I'm going to save save it and now I can add it right here and there we go it gets back to test one but hey let's actually show the file that's there so this div can have a class name equal to flex Flex D1 justify Das Center w- full for full width padding five and en large devices padding 10 okay that just gave it some padding but now let's actually render the image it's going to be a self-closing image that's going to have a source equal to file URL it's going to have an Al tag of image it's going to have a class name equal to fileuploader das IMG and there we go finally let's add a P tag right below that's going to say click or drag photo to replace and let's style it a bit by giving it a class name equal to fileuploader das label and we have to put this outside of this div right here but within a react fragment so here we can put a react fragment close the div and then put the P tag outside of the div but inside of the fragment if we save it that's looking much better so now we can add a caption we can add a photo location and the tags and click submit the file uploader is done but let's actually implement the logic for adding all of these other fields first of all the form fields are complaining that this doesn't exist file doesn't exist caption doesn't exist and that's because we haven't yet validated our form using Zod so right here we can Define what our form should accept this form should accept a caption which is going to be if the post exists then post question mark. Caption This is for when we're editing else it's going to be an empty string the file is going to be an array of files location is going to be if we already have a post location then post location else an empty string and tags is going to be if we have a post then post. tags. join by a comma else it's simply going to be an empty string now you can see that it's complaining that this caption does not exist that's because we are now using a default form schema but we actually want to turn this into post validation so let's head into our validations right here and we can duplicate this sign inv validation right below we can call this something like post validation it's not going to have an email not a password but it's going to have a caption of a type z. string it's going to be a minimum of about five characters and a maximum of about 2,200 characters let's also have a file which is going to be z. custom and we can Define the value right here of file or rather an array of files there we go it's so handy how we can Define custom types it's going to have a location which is going to be of a type z. string let's do Min of two Max 100 and then tags is going to be a z. string there we go so now we have this custom post validation and we can use it right here three times where mentioned the form schema and then you have to import it from lib validation there we go so now our post knows what we're trying to render oh I just noticed here we're using the input we have to spread the field so we have to say do do dot field like so and also we have to do the same for the last one right here do dot dot field there we go we're getting there we have a couple more errors as you can see we don't need this form schema as we have created it in another file file it's also complaining about what we're receiving here typescript is also complaining about the type of our props here so we can say this is going to be of post form props and we can Define it right here by saying type post form props is equal to where we have a post question mark meaning sometimes it's going to be here sometimes it will not and this is of a type models do document and this models is going to be coming from aight we also are never using a form description and we can now structure this more nicely by putting it in a single line there we go so now we have our form which we're almost there we can actually put the values in the validation is working as you can see we can upload images add a location and add tags the last thing we have to do is implement the logic what happens once we click submit and this is where we're going to connect with aite and create a new post based off of these values within here we can now use this new hook coming from react query so let's define it right here at the top by saying const mutate async which we can call create post and is pending which we can call is loading create that is equal to use create post and we can import use create post coming from queries and mutations now that we have it we can simply call this create post right within onsubmit the way in which we're going to call it is const new post is equal to to await create post to which we pass an object where we spread all values of a post and then pass the user ID of a type user. ID of a user that has created the post once again how are we going to get the user that's creating the post well that's pretty simple we have created our context so now at the top we can say cont user is equal to use user context and we can import this from Context o context and immediately you get the ID so now we have this new post and what do we want to do once we create it well we can say if there is no new Post in that case we can return a toast that's going to have a title of something like please try again and this toast is coming from const toast is equal to use toast coming from UI use toast there we go what happens if we successfully created a new post well in that case we simply want to navigate to the homepage so to be able to navigate we have to import use navigate from react router Dom let's do it right here import use navigate from react router Dom and then we can simply Define it as a hook cons navigate is equal to use navigate and then we call it right here navigate to forward slash make sure to make the onsubmit an async function because we're using the await action of create post so with all of this I'm hoping we're successfully creating our post if we get redirected to the homepage it means we're good so let's expand it to see it in full glory and let's create our first post I'm going to add our photo right here I'm going to say something like nice Greenery on a nice River not as thoughtful as Chad jpt but what can you do and we have a location I'm not sure where this is let's do something like River and we can add something like nature finally let's click submit we got redirected but it does say please try again so I'm guessing it broke somewhere let's open up the inspect element and then let's go to our console and it says the current user is not authorized to perform the requested action okay that's interesting that could be because we haven't set up the permissions for us to upload new items so let's go to app right let's go to storage media and then here settings and we can add a new role for any to create read update and delete different assets from our storage just to be sure let's go to database snapgram post and it's good it wasn't actually created so that's what matters so now let's give it one more shot I'm going to do something like River and nature I'm going to upload the post one more time I'm going to add a location something like a river and I'm going to say nature right here as well and I'm going to click submit we indeed get redirected this time without any errors but we still cannot know whether the post was actually created or can we if we go to aite and go to posts and reload we can see our first post appear right here it was created created on this date and it has this data liked posts name username account ID email bio image ID image URL save everything is here so we know that the post was created in the database but was the image created in storage let's check that out under media we have our preview.png and we can see this image on aight server this is amazing so now the last thing we'll have to do is implement the homepage and fetch this phenomenal post we've created so let's do that next to create a new post we first have to create a function that's going to do so in aite before we can call it so let's go ahead and let's go to our source lib aight API and right here below sign out account let's export async function create post that's going to receive a post of a type I as an interface new post coming from add for/ types make sure to import it and then we can open up a new try and catch block you know the drill right in the catch we can simply conso log the error but in the try is where the magic happens here first we need to upload our file to aight storage let's write that down upload image to storage so we can say const uploaded file is equal to a wait upload file where we pass the post. file0 meaning the first post now this upload file function is another function we'll create let's do it right below export a sync function upload file that accepts a file of a type file it's going to have a try and catch block within the catch we're going to consol log the error but within the catch we can say con uploaded file is equal to await storage. create file so the first time in this application we're diving into the storage functionality remember we had account databases avatars but now also storage this is used for saving media we want to pass a couple of things we first want to pass the storage ID by saying upright config do storage ID then we want to make a unique ID by saying id. unique and then want want to pass the file which we actually want to upload finally we want to return the uploaded file so now from the function above we get this file back and we are ready to attach it to a post that we're about to create in a database just to be sure we can do one check if there is no uploaded file throw an error else we need to get the file URL so we can say const file URL is equal to get file preview to which we have to pass the uploaded file. dollar sign ID and this get file preview is another function we'll create because we'll want to reuse it multiple times across this application so let's create a new export async function get file preview it's going to get one program of file ID of a type string into it it's going to have a try and catch where we consel Lo the error in the catch and in the try we need to get the preview so we can say const file URL is equal to storage. getet file preview here we first need to pass the app config do storage ID we pass the file ID we want to get and then we specify the width and the height which in this case I'm going to set to 2,000 then we specify the gravity meaning where is it going to show in this case we're going to say top and finally you specify the quality in this case we're going to get 100 the top quality finally once we get it we can simply return a file URL now we can go back to the function above we now have our our file URL and just to be sure we can add an if check if no file URL throw a new error but also not only do we want to throw an error we also want to delete a file because something was corrupted something wasn't right with it so let's create a new function delete file to which we're going to pass the uploaded file do dollar sign ID there we go so we're thinking up front if something was corrupted we want to delete the previous file and let's create this function export async function delete file which once again accepts a file ID of a type string of a file we want to create it's going to be a try and catch block with the Consol log of the error right here below error and then here we can say await storage. delete file to which we pass the upright config storage ID and the file ID of the file we want to delete and we can return an object with a status of okay there we go so now we're also dele deleting a file and now if we have successfully created a file if it isn't corrupted then we are almost ready to create a post but first we have to deal with the tags so we need to convert tags into an array we can do that by saying cons tags is equal to post. tags question mark. replace we want to replace all of the empty strings so we can do a regular expression like so so globally we're looking for all the spaces and we replace it with an empty space and then we split them by a comma so this will ensure to then split all of our tags or we can say just an empty string and finally we are ready to save the new post database by saying const new post is equal to await databases. create document first we pass the database ID we want to update so ight config database ID then we pass which collection do we want to update by passing the upright config do postcollection ID we Define the unique ID that we want to create meaning the post like so and then we need to pass the entire object object containing all the data about the post such as creator of a type post. user ID the caption which is going to be of a post. caption image URL which is going to be a file URL image ID which is going to be uploaded file. doar Sun ID location which is going to be post. location and then tags which is going to be set to tags and now this is saving this new Post in the database finally we want to check if the new post was created so if no new Post in that case we again want to delete this file so we can call a wait delete file and we want to pass the uploaded file. doar sign ID because something went wrong and we want to throw a new error finally finally if all of that succeeded we can return a new post and with this we're done with the creation of our post we're building a production ready application so we have a lot of checks we need to ensure that everything is going well if it doesn't go well we have to delete our file not to overload our storage right so this is now our function that will create a post now we have to call this create post as a mutation so we go back to our react query queries and mutations we can collapse the existing ones and create a new one right here below we can export const use create post then we want to say as before return use mutation to which we pass the mutation FN as in function that's going to get in a post of a type I new post and we want to call a create post to which we pass that post of course we have to import the create post from where we just created it at upright API and also the I new post from at/ types but now this is not the only thing we want to do once we create a post we also want to query all the existing posts so we can show them on the homepage so let's say const query client is equal to use Query client and then right here after the mutation function we can say on success so what's going to happen on success we create this callback function and say query client. invalidate queries and here we can pass the filters based off of which we want to invalidate the query specifically we want to choose a query key which is going to be something like posts or rather in this case not posts but get recent posts why is that and why do we need to invalidate it well that's the beauty of react query it allows us to fetch new fresh data and not let the data go stale so the next time we try to get recent posts it actually invalidated this query which means that it will not be able to get post from cash rather it will need to recall it again from the server so that's why we have to do it this way and invalidate the query for the recent posts after we create a new post I hope that makes sense now later on we're going to have many of these query keys and it's a good idea to keep them somewhere and keep them safe so what we can do is create a new file right here in react query called query keys. TS and there we can define something known as an enum so we can say export enam query keys this is an enumeration what it means that we can Define or connect one key with one string for example get recent posts is going to be a string of get recent posts now why do we have to do this well that's because if you just misspell something here like get posts like this or get recent post maybe that's even a bigger misspelling it might be really really hard to notice almost impossible and you can spend hours looking for this bug but on the other hand if you do something like this array query unor keys. getet recent posts it's impossible to miss it because you can import it specifically from query keys and then you know it's going to be right and now if I misspell it here it's going to immediately complain so this is a pro tip when building large applications how to save yourself from typos create an enam where you'll be able to create more different versions of this so in the description down below you can find all query keys. TS it's going to be just a couple more and we'll use use these later on to invalidate specific queries so we can always keep our data fresh great so now we have our use create post mutation and we can call it within can you guess where within post form yep we finally got there we can start by creating the structure for our homepage we're going to have a div that's going to have a class name equal to flex and flex x one so it expands within it we're going to have another div that's going to have a class name is equal to home Das container if we save this we cannot see a lot but it's there let's go ahead and move this over to the side so now it's easier to develop right within our home container we can create another div that's going to have a class name equal to home- poost and within it we can create an H2 that's going to say home feed there we go the first thing we can see here let's give it a class name equal to H3 dasb on medium devices H2 dasb text- left and w- full so now we can see it on the top left now immediately below we want to show some kind of a loader component if posts are loading so let's create a fake const is post loading which is going to be set to let's do true for now immediately below we can say if is post loading and if there's no posts and post is going to be set to null for now if there's no that then we can show the loading right here or rather a loader I believe we called it we can import it immediately and else we can actually create a UL that's going to allow us to Loop over all of our posts so for now we can see this great loading but now let's focus on what matters more and that is fetching all of the posts to fetch the posts we'll have to go to our queries and here we'll have to create a new query to get recent posts by saying export const use get recent posts this is going to be a function that's going to return a use Query no longer a Ed mutation rather a used query where the query key of what we want to get is going to be an array of query keys. getor recentposts and a query function meaning what will get executed once we try to fetch this this will have to be a function coming from aight so now we have to move to the aight API and create a new function export async function get recent posts where we can set the posts to be equal to await databases. list documents to that we have to provide the aight config database ID aright config dopost collection ID as the second parameter and then we can Define in which order do we want to get it so we can say query. orderes as in descending DEC based off of the created at criteria so the latest ones are going to appear on top and then we can also do another query. limit to 20 post tops and this has to be as the second parameter to our query just like this then we can fix this right here and we can say if there's no posts then we can throw an error that's going to look like this else we can simply return posts so now we can go back to our queries and mutations and we can simply say get recent posts import it at the top and now this use get recent posts is going to expose this function to get called so let's now go back right here and let's declare a hook that we can call Con where we get data so with every query you get something known as a data object and you can rename it to in this case post we get the not is loading anymore it's going to be is pending and that's going to be is post loading and then finally is error you also get that we can say is error posts and that's going to be equal to a hook of use get recent posts which we can simply import and call now if we save this it's going to automatically know whether we have to load something or not and as you can see the loading was immediately switched off and we can render test and as you can see we can see it that means that we indeed have some posts to load so let's create the UI for loading a post we can give this UL a class name equal to flex flex-all so they appear one below another Flex D1 a gap of nine for some spacing and a w- full for full width now here we want to map over the posts by saying posts question mark. documents. map where we get each individual post of a type models. document and the models has to be imported from aite and then we can instantly return An Li which is a list item that for now can render something like post. tile if we save it we cannot see anything let's see if I properly called it is it a title or is it something else well if I go to app right we can see we have the preview image this is under storage but if I go to databases database posts and here we can see all the attributes that this document has under data so we have likes caption yeah let's do caption post. caption now if we do it we can see River and nature which means we're getting it right here from aite from our own server database how cool is that but instead of Simply showing the caption let's show something more a nice looking post so to do it we can render a new component called post card this is going to be a self-closing component to which we're going to pass the post as the first and only prop there we go now this postcard of course is something we have to create So within components and then shared we can create a new post card. TSX run RFC and we can import it right right here within the homepage once you do that you can see the postcard and now within the postcard we are ready to implement the UI of the postcard first of all we know that it's going to accept posts as the prop so we can say post did we pass it as a post or posts yeah it's definitely going to be post because it's singular one so we can say post is going to be of a type post post card props where we can Define it right here at the top type postcard props is going to be post of models. document and this models is coming from app right so immediately know the structure of this document once we get it we can use its data and then render it so let's create a new div that's going to have a class name equal to post-c card that's going to create this nice rectangle we can also do another one right below that's going to have a class name equal to flex between within it we can create another div that's going to have a class name equal to flex items Das Center and a gap of three and then there we can render who created it so that's going to be this right here Hobbit with a photo two days ago and then tags that were added so let's create a new link and this link has to be imported so we can say import link from react router Dom that link is going to point to the Creator who created it so we can say two that's going to be dynamic forward SL profile slost doc creator. dollar sign ID here we can show the Creator's image by saying image has a source of equal to post question mark. Creator question mark. image URL or we can do a default of SL assets SL ions SL profile dplace holder. SVG there we go that's a huge the real JSM we can also give it an ALT tag of creator and a class name of rounded D full W of 12 and then on large devices h of 12 as well below that link we can render a div that's going to have a class name equal to flex flex-all and within it we can render a P tag that's going to render the post. creator. name okay that's better below this P tag we can render a div that's going to render a new P tag and within here we can show the post. dollar sign created at there we go so now we have the full date below it we can add some kind of a dash and then add another one that's going to say post. location there we go so now we have almost everything we need but let's go ahead and style it a bit better this first P tag is going to have a class name equal to base- medium this is going to make it Bolder on large devices it's going to be body bold and it's going to be text- light-1 the div below is going to have a class name of flex Das Center that's going to center it a gap of Two and a text of light three because it's not so important as the Creator name the P tag below can have a class name of subtle semi bold so it's a bit less important and a large devices small regular finally the last btag is going to have a class name of subtle D semi bold and a large devices small regular so same thing now the last thing we have to figure out is how to actually format this dat string into something that makes sense like on here we say two days ago and this my friends is the job for Chad GPT no longer do you have to create these functions on your own you can Google it or you can simply ask Chad GPT to do it for you so if you go to chat GPT say something like I have this date string literally like that I have this date string I'm building a social media app in JavaScript and I want to convert that date string into a more meaningful format like two days ago or two hours ago create a JavaScript function that does that okay I could have been a bit more precise but this is how we can do it as well hopefully it's going to give us something we can work with it created a function called format date and it showed us how we can use it so let's simply copy this function and let's go right here to our source lib and then utils dots within here you can paste this function and we can also say export function format date here our typescript is complaining a bit because I forgot to tell chat GPT to make it in typ script so I can simply say make it typescript that should do the trick right um let's see there we go certainly that's great so we can simply copy it again and it should have no problems at all we just have to export it there we go export format date now we can import this right here and wrap the post created at so we can say format date wrapid and then we can simply import it from l utils if we do that and go back you can see one day ago which is exactly when I posted it sometimes it's possible that Chad GPT is going to imagine something and give you wrong code so for that reason and for some other functions that we're going to use later on the full utils thats file is going to be in the GitHub gist down below it contains the function we just created as well as the check is liked which is going to help us later on and then another function called format date string but that's more or less it so now we can go back to our function it still works exactly as it should one day ago and now let's focus on the most important part which is showing some more details like the caption and the tags and then finally the image so we can go three devs down 1 2 3 and then here we can create a new link this link will only be shown if we are the ones that created the post because then we'll be able to update it so here we can say this is going to point2 slash update dpost slost dollar sign ID so it's going to point us to the update page and there we can render an image that's going to have a source equal to SL assets SL ions SL edit. SVG of course we want to make it a bit smaller so let's give it an ALT tag of edit and a width of 20 as well as a height of 20 there we go that's better now how can we hide this if we're not the Creator well first we have to know what is the ID of the Creator and then the ID of the currently logged in user how can we know that well we have done it a couple of times we can simply use the context so here we can say con user is equal to use user context and we can import it right here we can also say if there's no post. Creator then we want to return because something went wrong here but in this case we should have a user so right below we can add a class name to this link and this class name is going to be dynamic and it's going to check if user us er. ID is not equal to post. creator. dollar sign ID and if that is true it's going to render hidden and as you can see in this case it disappears although I'm not sure why did it disappear because we indeed are the real Creator oh it disappeared because this and and hidden should have also been within these brackets and then within double quoted strings there we go so now if we are it's there if we're not it's not there great now let's focus in more post details by going below the link and below this div we can create another link that's going to point to for slash let's make it Dynamic slost slash post. dooll sign ID so if you click this it's going to point to edit if you click anything above it's going to point point you to the real user or at least if you click the image but now everything that is within this link is going to point you to the post itself or the post Details page so here we can say div is a class name of small-medium on large devices base- medium and padding y off five there within a P tag we can render a post. caption of course this has to be wrapped in curly strings River and nature and Below we can have a UL to render the tags so we can give them a class name of flex gap-1 and margin top of two there we can render the post. tags. map where each tag is of a type string and for each tag we want to instantly return an Li that's going to have a key equal to it's going to be tag and a class name of text- light-3 and we can simply render hashtag and then the tag in this case it is simply nature and finally we can go below this div and render an image this image is going to have a source equal to post. image URL of course image with a lowercased eye or we can render for/ assets SL ions SL profile Das placeholder.svg and it's going to have a class name equal to post-c cardor IMG and an Al tag of post image if we save it we cannot seem to see it so it's it's like the image URL is not there let's consol log our post to see what does it contain so here we can consal log the entire post we can then go to our inspect element and go to the console and here if we reload you can see that we have a key error on home 17 so let's quickly fix that here we're mapping over the posts but we're not passing a key so let's say key is equal to post. let's do caption if we reload it is gone and now we have this post but the image URL is simply an empty array that's not good right same thing here the image ID is here but the image URL is empty so now we have to figure out where are we updating the image URL in in the first place apparently it's getting set to an empty array so let's search and let's search for image URL specifically we want to search where we're updating it not using it so here in the URL we're setting the image URL to Avatar URL but this is regarding the users we're wondering about the posts so most likely it's going to be would then create post and there we go here we say the image URL is equal to file URL and the file URL should come from the get file preview and then it's uploaded file ID so the first thing we can do is just conso lock the file URL to see what are we getting back so conso log I can put it inside of an object that way it's going to tell us what they conso logging so just like this and then we can try to create one another post so let's go back let's increase the width of the browser just a bit and then let's go to create post let's write a new caption say something like this time it will work I added the JavaScript Mastery logo right here and I can give location something like JSM and we can add nextjs as well as react and let's click submit you can see the file URL first was a promise and then fortunately the same thing even for the second image the image URL is empty but it's good to know that we got a promise right here as a file URL that's because if you go to the get file URL we made this function an async function and it shouldn't have been one because nowhere is it awaiting something so now we have to fix this by removing the async from the function and then we'll have to delete what we have already in the database as those posts are going to be broken so let's go back to our app right go right here we're going to have two different media files right now which I can completely delete there we go but we know that the storage worked so now I can go back to databases snapgram and then posts and I can also delete all of these posts right here there we go so now if we go back and reload and now back on the homepage we have no posts we do have one error saying that it cannot find assets images profile placeholder.svg so let's see what that is about let's try to go to profile dplace holder. SVG and we can see that indeed it is there so where are we trying to call it from let's try to search for profile Das placeholder.svg it seems like we're calling it in a couple of places assets here is it's icons but we have to verify is it icons or is it images so it seems like it's icons so here it's okay icons here it's okay icons icons and finally in top bar its images it should have been icons so if we save this and reload you can see that we have no errors and we have no posts so now that we have fixed the issue with the post creation we removed the async from our upload file or rather get file preview now it's going to immediately return exactly what it should which is the URL so let's close all the files that we don't need and let's simply create another post and hopefully this time we'll be able to see it on our homepage so I'll do something like ultimate nextjs 13.5 course I uploaded this great Dev overflow image which is the project we're building in our nextjs course I'm going to add the location of JSM Mastery Pro platform and we can add something like nextjs and maybe course and let's click submit there we go it got submitted and we can see it on our homepage that is great we finally have the real profile right here it says just now which is amazing we have the full caption the tags as well as the photo this is phenomenal and the last thing we need need is going to be the actions such as the heart and the save so let's go back to application let's collapse it to check it out on mobile devices it's looking great maybe this image is not in the right format but still it gets cropped properly so now let's go back to the postcard to finalize the last post actions So Below this link containing the image let's create a new component called post stats like this we're going to pass two things we're we're going to pass the post equal to post as well as the user ID equal to user. ID then we can create a new component in the shared components folder called post stats. TSX and run RFC immediately back in the postcard we can import post stats right here and then we can focus on the post stats component by first declaring which props do we want to pass we immediately know that's going to be the post as well as the user ID which are going to be of a type post stats props we can declare those right above by saying type post stats props is equal to a post is of a type models which is coming from app right dot document and the user ID is of a type string now that we know what we're getting let's focus on the UI and the ux of our heart and save stats first we can wrap everything in a div and that div can have a class name that class name is going to have a flex justify between items Das Center and a zindex of 20 to appear on top right inside it we're going to give it a div that's going to have a class name equal to flex Gap of two and margin right of five finally right within we can show the heart icon so let's say image that's going to have a source is equal to and let's do for now for SL assets SL ions SL liked. SVG and there we go but of course it's going to depend whether it has already been liked or not so if it has been liked then it's going to say liked otherwise it's going to say like which is going to show this different kind of an icon so we'll have to dynamically change this property for now let's leave it statically as like let's give it an Al tag of like let's give it a width of 20 as well as a height of 20 let's give it an on click which for now is going to be set to an empty callback function and let's give it a class name equal to cursor Das pointer finally right below it we can create a new P tag that's going to render the number of likes for now we can do it statically as zero and we can give it a class name equal to small- medium and on large devices base- medium there we go and we can do the same exact thing for saved so let's copy this entire div paste it below this time we don't need margin right as it's already on the right side and we need to change change this from like to save and everything else is going to be exactly the same so now we have likes and we have saves in this case we don't need to show the number of saves so we can remove the P tag there we go this is great so now that we've implemented the UI what do you say that we implement the logic for liking saving and unsaving as well we can do that quite easily by heading to our API file by the way I just press control or command p and I started typing the file name this is going to immediately move you to the correct file here we can create a new function export async function like post we have to get a post ID which is of a type string as well as a likes array that's going to be of a type string array we need this to know the IDS of the people that have liked the post as usual we're going to open up a new try and catch Block in the catch we're going to Simply consel Lo the error and in the try we'll try to like it by updating the record of the post so we can say const updated post is equal to await databases. update document and as usual we have to pass a couple of things to it you can see it right here as well aight has is really nicely documented their SDK so you have to pass the database ID collection ID document ID and then the data you want to update so let's do that first let's pass the database ID by saying app config that database ID then we have to pass the collection ID of the collection we want to update in this case app config that postcollection ID then you need to pass the ID of the post you want to update and then you want to pass has the data in this case likes of the new likes array so we know what is the new like count finally if there is no updated post there must be some kind of an error so we can throw it and we can then return the updated post and this is it for the like functionality of course we'll have to consume this function within our react query as well and make it a mutation but we're going to do that soon for now believe it or not the save post functionality is quite similar so we can simply duplicate this function below and call it save post to save a post we do need a post ID but we also need a user ID of the user that's saving that post of a type string then instead of updating the post we're going to create a new document so we can say do create document we pass the database ID but it's not going to be a post collection it's going to be a saves collection ID in this case we don't already have an existing record of that save so we can create a new one by running id. unique and then we simply want to pass the user as the user ID that's actually saving the post and we want to pass the post of the post ID so we know which post is getting saved and this is it we just return the updated post and finally we're going to also need to be able delete that saved post from the database so let's duplicate this one final time and let's recall it or rename it as delete saved post the only thing we need is the saved record ID so we can say saved record ID of a type string in this case we want to remove or delete a document so we can say databases. delete document when you delete a document you get back a status code and to delete it you simply have to pass the saved record ID as the third parameter then we can check if there's no status code we can throw an error else we can return something like a status of okay and now we have these three functions or we can call them mutations that we can use within our react query to then use them within our post stats component so let's go go to our queries and mutations and go right below our use create post and use get recent posts here we can export const use like post which is going to be equal to an eror function there we can define a query client by saying con query client is equal to use Query client and then we want to return the use mutation we need to pass a mutation function like so that's going to get as a parameter one object of post ID as well as the likes array that's going to be of a type post ID is of a type string and likes array is of a type array of strings and then we can have a function that we can call the function we're going to call is the like post coming from aight API and to it we can simply pass the post ID as well as the likes array and now it's no longer complaining because it gets exactly what it needs so now we have our used mutation but the second thing we can pass to our use mutation which goes right here after our like post after our comma is on success so the question is what do we want to do on success where we get some data back once we successfully do an action well we want to invalidate some queries so we can say query client do invalidate queries in this case it's going to be a query key of query unor keys. getet poost by ID with a data of that specific post that we updated like this so what does this mean well as I said before every single post that we get or fetch using react is going to be cached which is amazing because on subsequent reloads it will already have them saved and it's going to take so much less time to load them on the screen but if you update something about that post such as the like count and then if you go into the post details it's still going to have the same old like count the one it had before you actually updated it so to fix this we have to invalidate the fetch to theose detail details and say hey if this changes if you like the post the next time you open up the post please update the like count that way it's going to be reflected and we have to invalidate a couple of other queries as well so let's copy this one two three more times the second one is going to be get recent posts so if you just reload the home you need to be able to see a new updated like count then get posts just in general and then get current user because if you go to your profile you need to be able to see the updated like count and in other cases we don't have to pass the ID of a specific post because we're fetching many posts so it doesn't really matter great so this is the mutation for the use like count now as before with the API actions this time the use Save post is going to be similar to the use like post so we can simply dup duplicate this below we can rename it to use Save post and then we're getting the post ID as well as the user ID not the likes array so we can modify right here the type to user ID of a type string instead of calling like post we're going to call Save post and we have to import it from aight API and we want to pass the user ID as the second parameter or let's be careful if we have a r it says post ID and then user ID and here it's post ID user ID so you have to pass them in the same order in this case I truly did call it post ID and then the user ID so that's great on success we don't need to update the specific post get post by ID but we need to update all the other three so we can just do it like this and finally the last one use delete saved post is going to be the same so we can duplicate it one more time right below it's going to be called use delete saved post the only thing we need is one simple parameter right here of Saved record ID and then we can call a function called delete saved post which we can import from aite and pass in the saved record ID this has to be of a type string there we go and then we're going to invalidate the same queries so now we have three phenomenal functions which we can use to make the logic of our application work so let's save the file go back to the post stats and let's retrieve all of these phenomenal mutations and queries by using the hooks provided to us by react query that are by consequence using aite functions so back in the post stats we can see con mutate which we're going to rename to like post is going to be equal to use like post which we have to import from queries and mutations we can duplicate this three more times the second time the mutate function is going to be called save post and the third time it's going to be delete saved post of course we have to call this use Save post which we also have to import and use delete saved post which we can also import right here we also need to know who is the currently logged in user which we can get pretty easily by saying cons data rename it to current user is equal to use user context which we can import from o context then we have to figure out what are the current likes on a specific post and we can do that right here at the top Top by saying const likes list is equal to post which is coming from props right here likes. map where we get each individual user why user because we're saving a reference to the user whenever somebody likes it which is going to be type of a models. document and we want to return just their ID so user. dollar sign ID and that gives us the likes list then we want to create two Ed States so the first used state is going to say likes as well as set likes right here and at the start it's going to be set to the likes list so immediately we know it's going to be an array and we also have to import use state from react which we can do at the top by saying import use State we can also get use effect coming from react and in the same way we want to know if the post has been saved so we can say is saved set is saved and that's going to be equal to false at the beginning so now we have a lot of things we need to enable this functionality so let's create two functions we're going to use to like dislike and save and unsave posts const handle like post is going to be a function as well as const handle save post which is going to be another function for now now we have all of these properties we can work with right here Below in the UI so let's make use of them first things first we can figure out if a post has been liked and based on that we can show a different icon so instead of a source assets icons like we can open up a new Dynamic block and there we can say check is liked coming from lib utils to which we're going to pass the likes so we know the full likes array as well as the current user ID and we can check if it's currently in there if it is then we're going to show the liked feature like so and of course we have to close this properly so everything appears nicely and open up a new template string there we go so check is liked if it is we render the assets icons liked and else we want to render something like assets icons like if we save it you can see that now it's a zero and it's not liked later on once we click it it should turn out red once we click the like we want to get the click event and then call the handle like post to which we pass the event if the only thing you have here you pass there you can immediately just do a shorthand which means like this similar thing here instead of zero we can display the likes. length so how many likes there are and then we can do a similar thing with saved so we can open up a new Dynamic template string block and close it of course right at the top we can say if is saved if it is saved we can simply return assets icons saved. SVG else we can return something like assets icons save there we go and we can put it like here there is even a shorter way of doing this we don't have to create a template string because we're returning one string in any case same to here so we can remove this entirely and just say if is saved make it this else make it this same thing we can do here soest check is liked if so return this else return this and if we save it it's good right now it's not saved nor liked so it should be empty finally if we do this we can handle save post great so now you can see a lot of these are used likes is saved but the mutations are not used so what's going to happen once we actually click this button let's do that next in the handle like post we get one parameter of a Type e as an event and for now we can set it as react. mouseevent we also have to import react from react so we can do it here immediately within we can say e do stop propagation so this is not going to allow us to click any further it's just going to click this that's done in case you make this entire container clickable so it points to a post and then if you click it here it's only going to like it it's not going to do any any other action like go to the Post details then we have to update the likes array by saying new likes is equal to an array where we spread all the previous likes and then we need to check if new likes that includes the current user ID like meaning if they have already liked it and to make this code more meaningful we can even extract this right here and say const has liked is equal to this so if has liked see how much more sense this if now makes so if has liked in that case we can update the likes array or rather the new likes to be equal to new likes. filter where we're going to get the ID and we want to check if the ID is not equal to the user ID so we're going to keep all the likes besides the current like because we want to remove it and else else if it not has liked we simply want to call new likes. push and we want to append the new user ID because that user liked it too finally once we do that we want to set likes to be equal to new likes and we want to call the like post mutation so we can say like post to which we need to pass the post ID which is of a post. dollar sign ID and the likes array you can see typescript even lets us know what we have to pass right here it's going to be the new likes there we go but if we do it it's complaining that the argument type new likes is not assignable to parameter of type likes array so this is really good again thank you typescript we have to Define likes array and then pass new likes right here and now this is the function that's going to handle the like post and as you can see this is being used and then also this mutation is being used as well now let's do a similar thing for the save as before we can duplicate all the logic within our handle like post collapse it and put it right here within our handle save post we also need to get the react mouse event right here and then the logic is going to be even simpler we can delete everything right here and we can say if saved post record so have we already saved it and how are we're going to figure that out well let's define it right here const saved post record it's going to be equal to to the current user question mark. saave doind so we want to find if the record exists of a type models. document meaning is that user added to the array of the user that saved the post and we can check that by saying find where the record doore ID is triple equal to to the post. dollar sign ID there we go so now we're trying to figure it out if there is such a thing in that case we want to set is saved to false and we want to call the delete saved post to which we want to pass the saved post record do dollar sign ID so if we already have saved it and if we click it again we want to remove it from Saved and then we want to call the save post to it we need to pass the post ID of a type post. dollar sign ID and also the user ID and we can finally set is saved to true in this case of course it's going to handle both action and please take a second and notice if I've made a mistake here we have an if statement that delete the save but then every time as well we also called this that's because we didn't return right here if you add a return statement like so it's going to stop the execution of all the other blocks or an alternative is to also add an else here so we can say if it is not saved then save it if it is saved then remove saved here we go and now we can save this this gives us a lot of data to work with but before we go ahead and test it out typescript is trying to save us one more time it's saying property data does not exist on I context type and that's because I've made a mistake this should not be coming from the get user context it should be coming from use get current user which is a new function or a new query quy that we have to create this query is not only going to give us the user's ID and the name as we get from the odd context it's also going to give us more information such as which posts does the user have saved and based off of that we'll be able to figure out whether we need to save or unsave so let's go to our queries and mutations we can export const use get current user which is going to be an arrow function and we can return a simple use Query where we pass the query key of query keys. get current user and a query function which we're going to call is going to be get current user and this is coming from aight API we have already created this API function before because we we needed it for the context we can get it here as well and now if we go back we can import the used get current user and we can remove the import from the context there we go everything works typescript is not complaining so let's go ahead and test it out I'm going to press the like button really carefully because I'm scared we've done a lot of changes hopefully it works okay would you look at that it's saved and it unsaved not only that but it did it instantaneously the reason why that is happening is because we're using react query it does something known as an optimistic update before it actually updates it in the database it provides user with an instantaneous feedback now of course the key thing is if I reload the page is it going to remain saved and it does let's check the same thing with save oh it doesn't allow me to unsave it for some reason hm interesting let's see why that is so if we check this is saved it is set to is saved to false but then once I check it in the handle save post do we ever set it to false it seems like we do right here but what if I reload the page okay now it's unsaved what if I save it if I reload it is not saved so we have to be able to get the current Save State whenever we reload the page to do that we can extract this saved post record by copying it and putting it right here at the top then what we can do is create a new use effect and this use effect is going to have a typical callback function and it's going to change whenever the current user changes and then we can set is saved to be equal to saved post record um so if there is a saved post record we can return a true else we can return a false because this has to be a Boolean and there's a shorter way of doing this whenever you have something if that something exists return true else return false what you can also do is automatic Boolean assignment and That is do a double exclamation mark So what this does is it checks whether there is a Trudy value if there is a Trudy value this is going to you make it a falsey value and then from falsey you get the try so let me give you an example because I know this is a bit complicated if we have the saved post record which is let's say an object of Saved is true like this then we call one exclamation mark on Saved post record which is going to return false and then we call one more time this on the false and we get true if you were to repeat this with another true value like maybe just a string of test it would also return false because once you negate it you get a false and then a false is true but if you were to do this on a falsy value like if you were to do it on an empty string then at the end you would get false because first it converts to a true and then false I hope this makes just a bit of sense there we go and we can save this and we can reload the page now if we press save it remains saved but I still cannot unclick it okay let's see if I'm doing something wrong here I think that right here where I was checking for the saved post record the record itself is the user so I cannot compare the record of the user or the ID of the user with the ID of the post what I need to do is dive into the record. post the that user has saved and then compare with the post ID so now if I save this the saved record post or save post record should successfully get the state and now I can be able to toggle it on toggle it off but it looks like not on let's reload and see so if I do it here it's on yeah but it doesn't allow me to bring it back so let's just ensure that a couple of things are in order first of all if it's unsaved here go to app right and then go to the saves collection there should be zero documents because no post are saved if that is the case once you click it and now go back to aite and reload you should be able to see one save there but it looks like our user wasn't added and here it unsaved it so something is broken so let's try to click it once again this time it stays saved and if you reload right here it looks like it added another document with a again an empty user so this is not looking good it is possible that we got disconnected in the meantime so it doesn't know which user is there so for now what I'm going to do is I'm going to delete both of these two documents because we don't want to have any saves and I'm going to quickly log out and then log back in to ensure everything is good I'm going to use my same email and sign in now we can see we're logged in and now I click save but if we go right here it looks like it didn't yet save it so it's possible we need to add loadings for Save and unsave so right here with save we can say is pending and we can say is saving post and we can do the same here with is pending we can say is deleting saved and now we can use those two right here to display a loader so before the image we can say if is saving post or if is deleting saved in that case we can return a loader component which we have to import from loader else we return an image that's going to allow us to click it and then we have to close this block here so now if I reload the page it's going to say it's not or it is saved and here if I go we indeed do have a save document now if I unsave it oh the loading is in the wrong place I added it within the saved or handle like not save so I'm going to take this entire part remove it from here and add it right here there we go so it should be in the saved and now if I save it we can see that it's currently unsaved which we can also verify in app right and now if we save it again it was loaded and then it's saved so it's looking good here one more time I'm going to unsave it and go back it's gone we get a 500 and this is okay from time to time you will see some errors but that's because aight is still in beta it's going to be phenomenal once it's out so let's just reload it works again it's unsaved and one final time let's click save and check it out it is here so now the save functionality works perfectly as does the like feature as well this is great and with that we're done with the post stats with the queries mutations and apis for the Post stats as well you can remove the conso log that we had in the post card and we can focus not on the home right now but rather on the edit page because we need to be able to edit the post as well and trust me this is going to be simpler than you might think you have to go to the edit post page and then you can also open the create post page in here we can copy the entire create post and then paste it in the edit post we can of course exchange the create with edit post now it seems like we're creating one so we can simply change this to instead of create we can say edit and in this case we'll also have to load the existing post data so it's going to be a bit more complicated and create so what we can do is right here get the ID of the post we want to edit by saying const ID is equal to use perams and this use perams is coming from react router Dom so we can import use perams from react router Dom there we go and we need to get the post details so to get to the post details we have to create an API function so so let's go to our API below save post and delete saved post and by the way if some of these things are now working for you there's going to be a complete apit TS file as well as the queries and mutations file down below so let's create a simple get post by ID by saying export async function get post by ID where we get the post ID of a typ string and then we open up a new try and catch Block in the catch we conso log the error and in the try we can get cons post is equal to await databases. getet document we want to get it from aight config database ID from the post collection so we can say app right config post collection ID and we can pass the post ID finally we can return the post post now we have this function and we have to consume it by react query so let's go to queries and mutations we can go below use delete saved post and we can create new one called export const use get post by ID here we can say return use Query where we're going to have a query key of an array of query uncore keys. get post by ID like this and we need to pass the post ID in it and this post ID is coming as a param to this function so we can say post ID of a typ string finally which function are we going to call to query this post we're going to call the query FN which is going to call the get posted by ID to which we pass the post ID and this of course has to be imported from the top right here from aight API get posed by ID I think it's here there we go and once you do that we'll also have a special property called enabled so you want to set this defaults to disable automatic ref fetching when the query mounts or the query Keys is changed so we want to enable the fetching only when we're fetching the data for another ID if we're fetching it again for the same one then we're going to get the same details if the post ID didn't changed again this is a small step here nicely built into react query but it allows us to cache data and fetch data more efficiently so now we have this use get post by ID and we can go back to right here in the edit post where we can use it by saying const data is equal to post and is pending is equal to use get post by ID of course I have to spell it correctly and pass the ID and then we have to import it from queries and mutations the ID has to be a string so we're going to pass either this or an empty string then if we are pending meaning if we're loading the data in that case we can say return if is pending then we can simply return something like a loader like this which is coming from components shared loader but now once we do fetch the data what do we want to do with it well we simply want to pass it over to our post form with an action equal to update because now we're updating and a post equal to post there we go you can see the data was already populated how did that happen well more than that soon let's dive into the post form we can also accept the action and we can say that action is either going to be create or it's going to be update so now we know exactly what we're getting in and all the data automatically got populated because we're accepting this post right here as a prop but the question is how can we get the file to get updated as well because you can see right here we don't see the photo or the file and to get it we have to look into our file uploader component that we have created not that long ago to it we're passing the media URL post image URL so it should be able to read the image we're showing so if you go back to the homepage and click edit it should be able to read it but it doesn't so let's simply conso log right here at the top whether we're getting post dot image URL so let's conso log the post. image URL and then we can save it this post is coming from let's see here it's saying that sometimes it's undefined so we have to add a question mark so our app doesn't break that's great now let's open up the console and let's reload and as you can see we indeed do get a post which is our exact image which is great so we just have to figure out how to show it right here in the photos and that's most likely have to do with going into the file uploader and then using the media URL yes as you can see we're currently not using it so we can simply set the media URL to be a default State the default file URL and if we do that immediately it gets updated so now if we reload as you can see once you visit the create route it's empty but if you go to the edit you can see right here that it nicely gets all the data the photo as well and now you should be able to resubmit the form to then edit the actual details don't click it just yet because if you click it now it's going to create another post because if you go to the edit or onsubmit in here we're only calling the create post but we're not calling edit post which we have to create so one thing that I noticed is that here it's complaining that action should be update with an uppercase du so let's do it that way and now we'll have to focus on the logic of updating the post so let's do that next to implement the update post we can go to our API and right here we can add a new function called update post to do it we might as well copy the initial create post that we had here because a lot of the logic is going to be similar so let's copy it and then paste it right here below this time it's going to be called update post and we'll have to get the entire post want to update now the first thing we want to do is we want to figure out if the user is updating the contents as well as the image or if they're updating just the contents so we can say const has file to update and that's going to be true if the post. file. length is greater than one this can be above the try and catch block and then inside of the try we can form this new image by saying let image is equal to image URL is post. image URL and image ID is post that image ID and this is going to be of a type I update post so we can import it from the types that way we know it's going to contain the file as well as well as the image ID and the image URL now once we have the image we can figure out if the user has a file to update and if they do we can open this block and we can slowly start adding things to it so if they have a file to upload we want to get the uploaded file we want to check if it's there we want to get the file URL alongside the error Handler for the file URL put all of that above and then finally in this case we want to update the image by saying image is equal to we spread the existing image and then update the image URL with a new file URL and update the image ID with a new uploaded file. doar sign ID this here is going to be the entire image and the image has to be reassign so it has to be led but it's still complaining that image is never used we're going to use it really soon now we get the tags same things as before and then we want to save the post of the database but this time it's not going to be create it's going to be update once we update it we want to get the same databid same post collection but this time we're updating an already existing post so so we can get the post. poost ID right here and then here we can Define what do we want to update the creator doesn't have to be updated it's the same one the caption is post. caption image URL is going to be this new image object do image URL image ID is going to be image do image ID location is the same and tax is the same finally if we don't have this let's call it an up upd dated post then we can await delete file post. image ID so if something went wrong we're deleting the file else we're returning the updated post this is great this is going to enable us to update the post and while we're here let's also implement the delete post that way all of the cred options for the Post are going to be complete so we can say export async function delete post to delete it we need to be able to get the post ID of a type string and an image ID of a type string then what we can do is say if there is no post ID or if there's no image ID we can throw an error because we need those to be able to delete a post and we also need to delete an image which is why we need an image ID then we can go to the try and catch you know the drill in the catch we can conso log the error and in the try we can say await databases. delete document to which we pass the database ID the post collection ID as well as the post ID that we want to delete and finally we can return something like a status that's going to say okay there we go so now we have delete as well don't forget we have to consume this within a react query so let's go to query iies and mutations and before creating it we can simply copy the one before and then paste it here we can rename it to use update post we don't need to get anything inside of it in this case it's not going to be a query it's going to be a mutation so we can say const query client is equal to use Query client and then use mutation instead of use Query because this is a mutation an update not a fetch then we don't need to define a query key because we're doing a mutation and we can say mutation function instead of a query function in this case we need to get the post because we need to know what are we updating of a type I update post which we can import from types and then we can update post by importing this from aight API and we pass the entire Post finally we want to do something on success so on success we're going to get all the data and then call the query client do invalidate queries so if we update a post we need to update the query key under query keys. get post by ID because we have updated it and if you go to the Post Details page it needs to be updated and we can now duplicate this below this time we can call it use delete Post in this case we need to get two things into the mutation function so let's define them properly it's going to be an object of post ID and image ID and that's going to be of a type post ID is a a type string and image ID is a a type string as well and then we call not update post but rather delete post coming from ight API and and to it we pass a post ID as the first parameter and image ID as the second finally the query you want to invalidate here is get recent posts because in case we delete a post then we need to be able to refetch all the posts on the homepage to show all the new posts without the deleted one now that we have these options we can go back to the post form and we can import all of these actions or mutations from react query so right here below the use create post we can do something similar by duplicating this entire line mutate async in this case is going to be update post is pending is going to be is loading update and this is going to be use update post which has to be imported from queries and mutations now we can go right in our submit Handler and we can check at the Top If post exists and if action is triple equal to the update with a capital u in that case we say const updated post is equal to await update post and then we need to pass all of the options in it this update post is coming from our react query and of course it's doing the action from aight API so now we need to pass do do dot values meaning everything about that post we also need to pass the post ID of the post we're updating by saying post. dollar sign ID we can pass the image ID by saying post question mark. image ID as well as the image URL which is going to be post. image URL finally if we don't have the updated post meaning something went wrong it should say updated post then we can release a toast saying something like title is please try again and if it succeeds we can return navigate this time we're going to forward SL poost slash poost do doll sign ID so no longer are we going to the homepage to see the new post we created we're going to the details of that page to see that it was successfully updated great because we have this return here we don't have to wrap this in an else because once we update it's going to do this and exit if it's not update it's going to do this immediately great so now if we save this we're successfully doing the update action so let's try to say something like let's say the course got updated to version 13.6 and we want to add a URL so we can say URL is JS mastery. proo we can leave the location and this the same but it says submit maybe it should say something else so if we go down to the button in the button sometimes we need to disable it when it's currently loading so we can give it a disabled State and say if is loading create or is loading update then we want to disable the button so the user cannot just mash it multiple times and the button can say something like this if it's loading and if it's disabled the button should render the loader so we can say if is loading create or is loading update then we want to Simply return the loading State like so and if it is loading it can say something like post but it can be an action so it's going to either say create if we're creating or update if we're updating so let's just ensure that on the create post we're properly passing it here we're not so we need to pass an action equal to create and now if we go back as you can see on update we can see update post I'm not going to go back now to show you the create but you can trust me that on create it's going to say create now modify your original post and let's give it a run click update post and let's see what happens it says loading update post and we got redirected to the post Details page exactly as we wanted just to verify that the post indeed did get updated we can go to our posts and we can see if the caption contains what we added so that's going to be in the data and we can see that indeed it does so this is great so immediately the next reasonable step is to implement the post Details page as now our homepage is looking pretty good and the actions are there as well so let's focus on the post Details page next by going to post details and implementing its UI to implement the post details we first have to fetch the post details from the database and the way in which we can do that is by saying const data which we can rename to post as well as is loading or in this case is pending because we're using react query version 5 is equal to use get post by ID coming from queries and mutations to which we need to pass the ID the ID is coming from use perams so we can immediately import use perams which is coming from react router Dom and then we can say const ID is equal to use for Rams and that ID can sometimes be an empty string like so in case we didn't get fetch it from the perams great so now we have the F data let's go ahead and use it within our UI right here we can wrap everything in a div that has a class name equal to postore details Das container inside of this div we can check if we are currently loading so we can say if is pending in that case we want to return a self-closing loader component which we can import from components loader else we can return a div that has a class name equal to postore details dcard this is going to create this rectangle that you can see within it we can immediately render the Creator image as a matter of fact a lot of things from the homepage which we can see right here like the Creator image and all all of these details can be taken from there so let's go to our home and then we're going to go to the post card and we can copy this div that contains the link with all of the profile details so let's copy it all the way to here and then we can paste it right here within post details instead of this image that we just added there we go I can indent it properly we have to import link coming from react router Dom so let's get it right here we can also notice that post is possibly undefined so whenever we're talking about a post we have to add a question mark after so question mark here here as well and here with the location and we have to import the format date right here now if we go back to the post details you can see we have this the real JSM this is great but in this case we want to show it after the post so we can go above in the post details card and immediately here render a self-closing image that's going to have a source equal to post question mark. image URL with an ALT tag of Creator and a class name equal to postore details D IMG and this is not going to be Creator it's going to be the actual post there we go so now we can see the post and then we can see who created the post we can rename this div that contains the link into postore detailsinfo there we go and then we can wrap it all in another div this div is going to have a class name equal to flex between as well as w-o and now we'll have to put all of these details on the left side and then the button butons on the right side so let's do just that within this div we can put the link that points to the Creator image and that link can wrap everything all the way to the end right here and we can remove these characters that I don't need so now if we save it you can see the real JSM fits nicely and we can put this link within this new div that we have created with a flex between there we go of course this link will have to have a class name equal to flex so that all of these elements appear in a row it's going to have items Das Center and a gap of three and now we can go below this link and we can create those actions that we should have on the right side if at any point something breaks or doesn't look the same I know we switched a lot of code here you can go to the finished project GitHub repository and find the post Details page page now below this link we can create another div that's going to have a class name equal to flex Center as well as a gap of four within it we can create another link this link is going to render the edit image so let's say image is going to point to Source SL assets SL ions SL edit. SVG and of course if it's a link we have to give it a two property it's going to go to forward slash we have to make it Dynamic update dpost slost question mark. dollar sign ID and there we go we have a huge edit button we only want to show this if the person that created it is the author so we need to again know who is the currently logged in user to know that we can say const user is equal to use user context and we can import it and now we have the user so we can go back down and to this link we can apply a class name saying that if user. ID is not equal to post question mark. creator. dollar sign ID in that case we want to make it hidden so completely hide it in this case it's still there because we created it then this image has to have a width of about 24 and a height of 24 and an Al tag of edit it's much smaller we should also make this profile photo smaller as well so let's go to the Creator and we can make it W8 and H can be 8 as well but on large devices W can be 12 and age can be 12 and if we save it we have to say on large devices H is 12 there we go that's looking better and now alongside this edit we also want to add another button but this time the button is going to be for delete so we can say on click we want to call a handle delete post and we have to declare that function of course const handle delete post for now it be an empty callback function it's also going to have a variant equal to ghost it's going to have a class name equal to ghostcore details D deletor BTN and it has to have the same class right here to hide it if we're not the current Creator so let's copy this right here turn this into a dynamic template string and then we can paste it right here finally within the button we can render an image and this image is going to have a source equal to for/ assets SL ions SL delete. SVG with an ALT tag of delete a width of 24 and a height of 24 as well and there we go now we can see both of these we can also lower the Gap a bit maybe Gap two is going to be fine or even one looks good what if you do it with no Gap there we go even without a gap it's looking good and if you expand it keep in mind it still looks good on all different devices this is wonderful now don't delete the poe just yet we still have to add a caption in more details so let's go below this button and Below two more divs and then here we can create an HR a horizontal line with a class name equal to border w- full and border colar of Border D dark of 4 over 80 if we save it you should be able to see a really unnoticeable line that's going to create some spacing and then below we can copy everything we already had from a post card not the Creator things but rather all of the post tags the post caption and more so let's simply copy this div that contains the post caption it's just this small one right here we can paste it below the HR indent it properly and everywhere where we're saying post we can add a question mark as well and there we go we have this wonderful caption we can change this tiing a bit from this div by giving it a flex Flex Das Co Flex D1 w- full small- medium and on large devices base- regular there we go that's going to position it a bit better and finally we need to render the post stats so let's go below this div create another div that's going to have a class name equal to w-o and within there we can render a post stats self-closing component which we have to import from components shared post stats with a post is equal to post a use user ID equal to user. ID in this case it complains that a post could possibly be undefined so we can say post or an empty object so it doesn't break oh but the structure of an empty object is not the same as the structure that it should have so in the post stats we can declare the post as optional maybe it's not going to be there but then it lets us know please add question marks so the app doesn't break so that's exactly what I'm going to do I'm going to add a question mark whenever post is mentioned oh but then it's complaining that we actually need to pass a post ID to the save post so I'm going to add right here or an empty string or an empty string as well and now we are good so if we go back now we have the post stats and you can see the likes and saves as well on the bottom this is a real post Details page looking really similar as it does on the original Instagram application keep in mind that you can go to the edit which is great and you can also delete it which we're not going to do for now but this is wonderful and later on once we have more posts we're going to also Implement other post recommendations right here below this one so you can scroll through the app and find all the post that you like but with that said we're making amazing progress we have the homepage we have the create post page we also have the the edit page we can like and unlike save and unsave as well as visit the post details this is amazing so let's go ahead and focus on the second major page of our app which is the explore page here we're going to expand it further so no longer it will only be a home where we fetch the latest post we're going to have some search Logic we're going to have the infinite scroll logic and a lot more so let's get started with a explore next by putting this to the side and then opening the explore page to get started with our explore page we can first wrap everything in a div that's going to have a class name equal to explore Das container then within it we can have another div that's going to have a class name equal to explore Das inore container within that one we're going to have have an H2 this H2 is going to say search posts and it's going to have a class name equal to H3 D bold on medium devices H2 Das bold and w- full now right below it we can have a div that's going to have a class name equal to flex gap of one padding X of four w- full rounded - LG and a BG of dark 4 we are now starting to form the UI for our search so let's render an image and that image is going to have a source equal to SL assets slash ions SL search. SVG there we go and then we can give it a width of 24 and a height of 24 and then I'll tag off search finally let's create an input this is going to be a self-closing input component coming from components UI input it's going to have a type is equal to text a placeholder that's going to say search a class name equal to explore Das search and of course what would an input be without a value which is going to be a use state right here on top so we can use a state snippet and we can call it search value set search value as well and then at the start it's going to be set to an empty string and we of course have to import use State coming from react now we can use this search value right here and the input also needs something to modify that value which is going to be an onchange Handler this onchange is going to get an event and it's going to set search value value to be equal to e. target. value like so so we can immediately get the value and then modify it now let's go two devs below and then there we can start creating the what is about to become the popular the explore page so let's give this div a class name equal to flex Das between w- full for full width Max DW d5xl and margin top of 16 to divide it from the search and margin bottom of seven in there we can have an H3 that's going to be similar to this H2 and we're going to change the styling to be body- bold as Wells on medium devices H3 Das bold and we can change it to H3 there we go instead of search posts it's going to say popular today right below it we can can create a new div that's going to have a class name equal to flex Das Center gap of three background of dark three rounded Das excl padding X of four padding y of two and cursor Das pointer this is going to be a button to filter our posts so let's create a P tag that's going to say all at the start we're filtering by all we can give it a class name equal to small medium on medium devices base medium and text- light-2 for the color below this P tag we can render a self-closing image tag that's going to have a source equal to SL assets SL ions SL filter. SVG it's going to have a width of 20 a height of 20 and an Al tag of filter there we go so now this is looking really good and now we can go two divs below and we can show the results of what's popular today so let's create a new Dev that's going to have a class name equal to flex flex-wrap gap of nine between each post a W-4 for full width and a Max W of 5 XEL now inside of here we should figure out if we should show no post post or if we should show old posts so let's create some variables that are going to help decide what to show we can say const should show search results and that's going to be equal to if search value is not equal to an empty string then yes it should show search results then const should show posts it's going to be equal to if it's no should show search results I think I misspelled it show show it should have been should show so if no should show search results and if we have posts so later on we're going to have an array of post cons post is an array and then we'll be able to say if posts. pages. every page has an item where an item. documents do length is greater than zero that means that we do have posts but again this is just a fake array soon enough we're going to fix this but these two Boolean variables should allow us to know what we need to display so right here below we can say if should show search results then we can do a Turner operation and then we can show a new search results component like this else we can check if should show posts then we can do a P tag here and say end off posts because we have came to the bottom and we can give it a class name of text dl-4 margin top of 10 text- Center and w- full and finally we can render the posts so we can say posts. pages. map here we Rend it through all the pages where we get each individual item and and an index and we return something known as a grid post list this is another component that we don't yet have so it's going to result in an error right now but we can pass it a key equal to something like page- index as well as posts which is equal to item. documents so posts on that specific page and now of course everything is breaking because we have to create two new components search results and GD post list so let's do that immediately by going to components shared search results. TSX where we run rafc as well as grid poost list. TSX where we run rafc again now we can import both of these components right here but if we go a bit above and then comment out these posts because right now this breaks because the pages don't exist on posts so maybe we can add question marks right here to make this work for now that's not going to work so we can comment it out and the reason why it's not working is because these variables are not working as the pages don't exist under posts so we can comment all of that out and we're left with the base structure of course the next meaningful thing to do is to actually fetch real posts that we can explore and then implement the search as well so let's go ahead and let's focus on getting the post for our explore page and don't forget that in the explore page we have this wonderful infinite scroll so you'll always be able to get new content as you scroll down so let's go ahead and Implement that fetch posts you know the drill we first have to go to the API app right and to create this function we can create an export async function get infinite posts of course we're missing an N right here and it's going to accept an object called page peram which is going to essentially be page per Ram of a type number inside of here we want to define the queries which we want to fetch the post by so we can say const queries of a type array with any kind of content is equal to array of query. order descending based off of the updated ad property and we have to add a dollar sign up front so we want to get the newest post first and we want to limit it to query. limit of 20 10 is okay as well considering that we also have infinite loading then we want to check if we have page prrams so if page pram in that case queries. push we also want to add a query. cursor after what does this mean well it means if we're at the page two skip the first 10 already and give me the second 10 right so we can say page Pam do two string so the page param is actually going to be a number of how many pages or documents do we want to skip once we know that information we can open up a new trial and catch Block in the catch we can simply consel log the error and in the try we can try to fetch those posts by saying const posts is equal to await databases. list documents from a database with an ID of ight config database ID and the collection with an ID of aight config that post collection ID and then we want to pass all the queries BAS off of which we want to fetch the data if there are no posts we can throw an error in case there are we can return the posts that's it for the get infinite posts believe it or not but while we're here let's also do the search and that's going to be really similar to get infinite posts so let's duplicate it below let's change the name this time to search posts we won't need any kind of page Brams we'll need search term of a type string we don't need any kind of queries or page prams the only thing we need to do is fetch the posts so here we can have one specific query which is going to be query. search and we can search by caption and the search term is going to be the search term that we're passing through props there we go and again thank you tab script it's complaining that the search term should be not a second part of the array but rather a second part of this search object there we go and then we're returning the posts with that we're done with the search posts now as you know the drill we have to consume those within queries and mutations so let's say export const use get posts which is equal to a function that returns something known as a use infinite query this is a buil-in react query feature here want to pass a query key meaning which posts do we want to get and that's going to be query keys. getet infinite posts then we need to pass a query function which is going to be get infinite posts coming from aight API and then we have to figure out how we're going to paginate so we can say get next page for Ram which is going to contain the last page that we visited then if there's no data that means there are no more pages so we can say if we're on the last page and if last page documents. length is equal to zero then we can return null else we want to find the ID of the last page so we can say last ID is equal to last page. documents and then we want to get the last page. documents. length minus one this is going to give us the last page and then we can say that dollar sign ID of that page and we can return the last ID here it's complaining that last page is possibly undefined that's okay we know it will not be and finally we can do a similar one for the use search posts so right here we can say export const use search posts is equal to a function where we pass the search term of a type string and then we return a use Query where the query key is equal to query. keys and then it's going to be search posts and we don't pass the search term here we pass it under query function once we call the function so query FN is going to be a callback function where we call the function we created called search posts coming from aight API to which we pass the search term finally as before we have to do the enabled this means when is it going to automatically refetch when the search term changes and this is how we do it so this is great now we can consume both of these within our explore page in the same way we have been doing so far so right here at the top const data as searched posts and is fetching as is search fetching that's equal to use search posts coming from queries and mutations to which we have to pass the search value one cool thing about this is if we were to just pass a regular search value it would recall this every time that we enter a keystroke but this can be quite draining for our API and our server and everybody involved so usually what you want to do is you want to do it after a specific amount of milliseconds pass by then you want to do another call this is a method called debouncing so what you can do is close everything collapse all the files go to source and create a new folder called hooks within hooks you can create a hook called use debounce dots and this is a hook that I found directly from react query here they provided its entire code essentially what it does is as you start typing it de bounces the query so it saves you performance and this entire debounce query is going to be in the GitHub gist down below so you can simply copy it and paste it right right here once we have it instead of passing the search value we can define a new const debounced value which is going to be equal to use the bounce to which you pass the search value and then set in number of milliseconds like 500 until when it's going to be recalled and you need to import use de bounds from hooks use debounce and then you can pass the debounced value which is going to make our application even even more optimized so here we have everything when it comes to the search but above the search we can also Define const data as posts fetch next page as well as has next page which is equal to use get post and then we have to import this from queries and mutations now this gives us a lot of data to work with because no longer longer do we have to fake the posts now we can actually use these right here and we can uncomment what we have right here below if you do that and save it we still get an error but that's okay we can go to inspect and then conso and we can see that it's complaining that it cannot read undefined at Pages line 16 so that is right here apparently our posts still don't have the pages other errors also include I'm guessing something related to that yes so what we can do is we can conso log the posts and see what are we getting back if I reload the page once again it seems like the posts are undefined so let's figure out why that is one thing that we might need to do is just ensure that we don't get to this block of code if the posts are undefined and it seems that they are so what we can do is add an if state statement right here checking if we don't have posts and if we don't yet have posts then we can simply return a div that has a class name equal to flex D Center w-o and h- fool and this is going to render only one thing which is going to be our self-closing loader component coming from components shared loader if we save this you can see that our app works again and we can see that first the posts are undefined but then as soon as it loads them we get one post right here with the caption that we have entered so this is great and now you can see that we're displaying the grid post list great and we're passing the posts within them so what do you say that we try to show these posts on the explore page let's go ahead and go into the grid post list and let's implement it first things first let's get all the necessary props most important one is going to be posts so we can Define this as grid post list props and we can Define them right here at the top by saying type GD post list props posts is going to be of a type models. document but it's going to be an array of these models coming from ight now that we have the post here let's also get the user because we'll have to know which ones were created by the user so you know the drill const user is equal to use user context which we import from OD context now that we have this we can wrap all of this in a UL an unordered list that has a class name equal to grid Das container and let's save it you can see it disappears and now within here we can map over the posts by saying posts. map where we get each individual post and for each one we can return a list item for now let's say that we just returned a post. caption if we do it you can see only one post caption here but of course we want to make this a bit more interesting and something like this would be great an explore page where we can see all the popular posts we have a nice looking image a Creator in bottom left and then save and like on the bottom right as well and then we can Scroll of course with the infinite scroll as much as we want to down below so this is the goal and we can implement it so instead of just An Li Let's do an Li that has a key equal to post. doar ID as We're looping over it and the class name of relative m-w of 80 and H of 80 as well now instead of rendering a post caption right here we want to render a link this link is of course coming from import link from react router Dom this link is going to wrap our image so right here we can Define our image that's going to have a source equal to post. image URL and there we go so now once we click it we wanted to go to the Post details of this post so let's say two slost slost dooll sign ID now if we click it we go away that's great let's also give it a class name equal to grid Das postore link and that's going to make it look a bit better the image itself is going to have an Al tag of post as well as a class name of h- full for full height w-o for full width and object cover so it looks good there we go now below this link we need to show the information about a user but we're going to reuse this grid a couple of times we're going to reuse it on our profile later on as well specifically on liked posts and more and as you can see and on the Explorer we're going to show the stats like save and like but if we're visiting somebody's profile we don't necessarily have to show the stats because you're not going to like your own posts so that's why we're going to make this component modifiable as every component should be we can pass some additional props such as show user by default set to true as well as show stats also by default set to true but in case you want to pass a false you can do that so right here at the top we can also add two new types show user question mark meaning it's optional of a type Boolean and show stats question mark Boolean which means that it is optional so now if we go below this link we can create a new div that's going to have a class name equal to grid dstore user and within here we want to check if show user is true then we want to return a div that's going to have a class name equal to for now flex and it's going to render an image that's going to have a source equal to post. creator image URL and now you can see it right this is the little image that we need to show of who created the post we can give it an Al tag of Creator as well as a class name of h-8 w-8 and rounded Das full as we usually do with profile images and there we go now it's a little profile icon on the bottom left we can also create a P tag that's going to render the post. creator. name and we can also give it a class name off line- clamp D1 which is going to ensure it fits in one line let's also add a couple more properties to this div Flex items D Center justify Das start a gap of two to divide them a bit and the flex of one great now we can go below this div and below the dynamic block and we can also check whether we want to show the stats if we do want to show the stats we can render the post stats component so post stats like so we can import it from Post stats pass over the post equal to post as a prop as well as the user ID equal to user. ID as a prop if we save it you can see like and save and we can do that right here from the explore page this is great now our explore page is almost done we still have to do the search of course but let's go ahead and add another post to see how it looks like let's go to create add a caption something like learning nextjs 13 select the photo add a location something like add home and add tags such as nextjs learning coding and we can create a post this right now works pretty flawlessly I got to say we get redirected to the homepage and we can immediately see our new photo like a real social media application our timestamps work as well so just now at home we have different tags and we can click it to go to the Post details we can like it and we can also of course head to explore where the new photo now appears at the Top This is is great now what do you say that we focus on the search next so here we have a component called search results and if you remember we have already created the searched post right here so let's pass some of the values into our search results specifically we can pass the is search fetching which is going to be the loading State equal to is search fetching as well as the search post which is going to be a query request coming from our used query finally we can head into this component and we can start implementing search the first thing we have to do is accept those two props by saying is search fetching and search posts and this is going to be of a type search results props we can of course Define the type right above so type search result props it's going to get the is search fetching which is going to be a Boolean and search posts which can be a collection of models dot document and an array and we can import that from aite now how is our search going to look like well our search is going to be a really simple component as a matter of fact it's going to be almost like an if so we're going to return a couple of different things if we're fetching the search posts we can simply return return the loader component which we have to import from loader on the other hand if searched posts exist so if search posts. documents. length is greater than zero then we want to return the same grid post list that we have already created but this time we want to pass something else to it so I'm going to put it in a new line like so and we can also put this in a new line so it's easier to understand it's a real function block there we go so we want to return this grid post list and we need to pass to it posts which now are not just going to be explore posts but rather searched posts. documents there we go here tapescript is complaining a bit I made two mistakes first of all I have to spell this prop correctly and when it comes to the search posts it's complaining right now that it does not exist on this property we can add a check right here saying if search post exists then we can go ahead and check for the documents this is just a top script warning we can look into it later and here it's saying cannot find search posts did you mean search posts yes we indeed did mean that so that's good thank you tsrip for letting us know and then we're passing the search posts into the grid post list finally if this is not true and this is not true then it must mean that we have no searched posts so we can simply return a p tag that's going to say no results found and then we can do a class name of text dl-4 margin top of 10 text- Center and W Off full and this is it this is our search results component that we have here and that we're using within our search results here we have a warning from typescript this is okay for now we can come back to it later on so let's go ahead and test our search we can try searching for something that we have on our homepage for example nextjs 13 appears in both we have learning here and we have ultimate here so let's try to search for something like that let's try to go for next.js it's loading and we get both that's good both say 13 but only one says 13.5 the other one is 13.6 so if we do this this it seems like it's not ref fetching it it just gives us what's already cached so let's go into our query for the search that's going to be search post use search posts and then here we have to validate the query again once the search term changes so we can pass the search term here as the second parameter and now it's going to recall it 13.5 and then 13.6 we still have both but if we search for ultimate we only have this and if we search for learning we only get this which means that our search is working properly this is great to see of course there are filters here that we can also do and in general if we don't have search then we have the explore of course this is the place where we're going to also implement the infinite loading so we can immediately fetch all of the next pages and all of that is going to be pretty easy to implement using react query and aite so what we can do is first of all go all the way down and below this div we can create a new Dynamic block of code that says if we have a next page so has next page and if there is no search value meaning we are on the explore and then we want to show a div that's going to have a ref this is really important a ref called ref and a class name of margin top of 10 of course the app is going to break now because we haven't yet created this ref and we can add a loader right here when we're loading for the next page now why are we adding a ref to this little div right here at the bottom well once we scroll to it and once this reference gets in view it means we're at the bottom of the page and we want to start loading the new posts so let me show you how to implement that right at the top we can install a new package this package is called react intersection Observer you can see it right here on mpm you can implement it in Hooks and it's going to give us access to this use in view it's going to be really easy to monitor specific elements in this case that ref at the bottom the only thing we have to do is import it attach a ref to it and then we're going to know once we reach the bottom of the page again don't read when the wheel when you can find a simple package like so and we can easily install it by running mpm install react intersection Observer there we go the package got installed and we can use it by importing the use in view hook coming from react intersection Observer now right at the top we can declare a new ref const ref and in view which is equal to the call of the used in view hook just like so and then we can also import use effect coming from react we can Define it right here at the top by saying use effect don't Define it below the if statement use effects have to be above all conditional renderings and it's going to render whenever the inw variable changes or whenever the search value changes what we want to do is we want to check if it is in View and if we're not searching for something so if there's no search value then we want to fetch next page and this is my people how you implement infinite scroll so let's save it let's go back to application and now as you get to the bottom you should be able to see the scroll up of course it's not going to give us anything right now because there are no new posts but if we limit the number of of posts per page and if we create more posts it's going to work we can test it out really soon so up to this point we've implemented a lot of stuff so let's close these files let's expand this to its full glory and let's see what we have implemented up to this point we have a phenomenal registration and login screen so here we can login into our account or we can sign up for an account if we don't have one already and in this case we can log in with our password and email immediately we are redirected to our home screen where we can see our great posts each post can be liked unliked and also saved let's not forget that we also have a phenomenal explore page where we can see more posts that are popular today if you want you can add additional filters and we have complete search search so if you search for something it's going to show up and also lead you to that post Details page also don't forget that everything is completely mobile responsive and it has this native mobile UI we've laid down the foundation for creating something extraordinary a fullblown social media application of course there's a couple of pages that are missing such as the People page where we show all the users the saved page where we simply have to fetch all the saved posts and then display them these two pages look like this here you fetch people and you show them and if you notice the saved it's going to look almost exactly the same as our explore that's because we're reusing the same grid component finally there is the profile page where we can see the likes as well and the edit profile but I want you to pause here for a second first of all congratulations on coming this far into this tutorial it has been a long one you've shown a lot of dedication to learning and trying new things out so pat yourself on the back and be proud over the years many of you have asked me how I approach something or develop something that mindset that developers have and today I want to do something special I want to tell you how I approach things for the rest of the features that we'll be building today if you see many people are successfully able to do something by following a tutorial like this or other content but their real struggles begin when they're faced with something new most of us will still be clueless even though we have done something similar before by following a YouTube tutorial this is known as tutorial hell and in our nextjs course we have tried to solve that we have created a So-Cal active lesson learning where you still have all of the lessons that we usually us have such as setting everything up and coding things from scratch but soon enough we dive into something special and that is active lessons they start from the sidebar and then whenever you want to implement something before we do it together you have to do it on your own let me give you an example for the homepage here you have to create a question card UI so here we have a complete active lesson that guides you how to do that specifically with the mindset part teaching you how to approach it like a real developer it gives you something to think about additional resources and even hints that you can uncover by hovering over and then in the next module I teach you how to do it from scratch in a long lecture and why am I telling you this well I don't really believe in tutorial hell watching tutorials is great but what I believe is missing is the thinking part when you're watching a video you have to stop and ask yourself how would I approach it and only then watch the solution but very few of us do that and this is why we blame it on tutorial hell and why you're missing that developer mindset that's why in our next GS course we have scattered around so many of these active lessons so that you can actually learn by building remember good developers don't have someone holding their hands they figure things out on their own because they have developed their mindset I don't have any graphics right now but just pause for a second and listen there's an old saying that says give a man a fish and you'll feed him for a day teach a man how to fish and you'll feed him for a lifetime for that reason in this free YouTube video I want to give you a glimpse of what we have in our course by introducing some active lessons for the remaining pages to see how you will approach building them I hope you're excited to continue with this project by learning while doing so let's get started and I proudly present to you active lessons for our snapgram application the link is going to be down in the description the first active lesson is about implementing the infinite scroll and this is the feature that we have already built so I have specifically introduced this one to go over it and to show you how you're going to do the future ones on your own now that you know how we did this one together so the task and the mission is to think and try the infinite Scrolls in the application for the home users and profile Pages even though we have already implemented it for the explore page you can also make it go right here in the homepage so here we provided you some examples saying that you can visit the original Instagram application and then see how every time you scroll down new posts appear and then some additional resources as well such as the query key query function infinite query app pagination aate queries and more all of the resources you need to make this possible of course most of these are actual documentation sites and then there's also a mustre resource which is a react query article on infinite scroll finally we have some hints as well the entire process needed to develop this is nicely laid out in form of hints and not only that it urges you to think and develop that developer mindset so it asks asks you what do we need how should it work or Ro does that mean that Instagram is showing many posts in one request and then even some code blocks to get you to implement this on your own in case you get stuck and need any assistance as you can see it goes on and on and on and gives you the code needed to implement these features within the application we have been building so far how cool is that it's a completely new paradigm to learning so just give it a go and tell me how you like it and once again if it's not working as expected don't feel frustrated it's a part of the developer's life so start again and debug everything line by line see if you're getting any documents and check if the last ID is being calculated properly and whether it's being passed to the query function or not just keep trying if you get stuck just refer to the finished code repository on GitHub this right here was just the first of the active lessons we have implemented it for explore page but you can do it for the homepage as well and then we have five more the top creators is the next feature you have to implement and in this case we have even provided you with a figma design you can see it here so you have to implement the top creators right sidebar once again you have everything you need here we even recommend to play a little flexb game to test out your Flex skills and then again we dive into a large number of different hints they go linearly from start to finish so you can try coding it on your own and then try to think in layouts try to implement different things try to do it on your own but if you get stuck you can visit the hints then again we're going to implement the all users section next here you can check out the design and then we go through different must plays or must reads as well as some additional hints you can follow to implement the feature and I don't think I got to say it but this is repeated for the save posts for the edit profile and finally for the profile page itself I truly believe that this is a new way to learning of course feel free to let me know what you think down in the comments and if you'd like me to do more things like this in the future with that said give it a go try to go through as many of these active lessons as possible see how you like them try to implement some of the features and then come back to this video to deploy the project to the Internet so how did it go I hope you are able to take your time and I know it can take a lot of time maybe even more than the entire video you've been watching because implementing things on your own actually challenges you a lot so I hope you did good if not there's more things to do and more things to learn but learning means improving so in any case now however much of the project you've finished let's go ahead and deploy to the internet to get together we'll be deploying our project to versell so you can head to versell decom and log in or sign up once you log in you should be able to see your projects and you might not have as many as I do as you can see we have hundreds and hundreds of projects right here most of them belong to our JSM masterclass experience students so in our master class which is the JSM boot camp we actively teach people how to develop projects on their own within a team and this can be considered even an additional step to these active lessons the active lessons though are reserved for the nextjs course Andy will also gotten a chance to experience them in this video so with that said let's go ahead and click add new and we can select project you can notice that it's going to ask us to import a get repository which means that we have to upload our project to GitHub and to do that you can go to github.com slne and create a new project called something like snapgram you can make it public or private I'm going to make it private in this case and click create repository once the repo is there we can push our code to it by dragging this to the side opening up our terminal of course we have to stop it from running and then you can run get init get add dot get commit Dash first commit and then you need to copy a couple of command from here such as git Branch M main get remote at origin and get push you origin Master once you do it our code should now be live on GitHub which you can see if you simply reload and there we go our code is here now that repo is live we can go back to versel and it automatically figured that we have a new V project right here here which we can import once you import it you'll have to add your environment variables so back in our code you can go to our env. looc copy all the variables and simply paste them right here it's going to automatically figure out all the individual variables and click deploy as you can see the deployment is cued so let's give it a minute and let's see if it's successful and in just 30 seconds our website is now live and and let's go ahead and click here to visit our deployed application there we go our sign in is looking great but if you go to inspect and if you look into the console you can notice that we cannot really make a request to our new domain or rather the access to ight is being blocked from our new domain that's because of the course policy something that developers don't really like but thankfully there's an easy way around it you need to go to aight and then you need to add a new platform in this case we're going to do web the name is going to be snapgram and the host name can be everything ad verell thata and we can click next finally let's skip optional steps and this created a new integration with a web platform where we have deployed our snapgram and every single host name on verell should work so let's go back clear the the console and reload the page we immediately get logged in into our new domain if that hasn't worked for you you can just manually log in and with that said you should be able to have this explore features the people as well if you have implemented it saved features as well everything is working flawlessly on our newly deployed website how great is that so how did you like the build if you're watching all the way until the end I hope you loved it Andy and how did you like the new active lessons I hope they truly tested you and helped you build your own developer mindset if you want to improve your game and build even better applications now using nextjs instead of react you can do so in your nextjs 13 course so just go to jm.pro and check it out within it we have many more active lessons and a lot of interesting things to learn to land a developer job and finally huge thanks to aight not only for sponsoring this video but for building such a phenomenal open-source platform that lets us add OD databases function and storage in a matter of minutes once again thank you so much for watching and I'll see you in the next one have a wonderful day
Info
Channel: JavaScript Mastery
Views: 315,566
Rating: undefined out of 5
Keywords: javascript, javascript mastery, js mastery, master javascript, javascript mastery react js, javascript mastery portfolio, javascript mastery react, tailwind css react, tailwind css tutorial react, react, react query, react query tutorial, react js, react context, tailwind css, react js tutorial, react js full course, react js project, react.js, react.js project, react.js full course, social media app using react js, social media app react
Id: _W3R2VwRyF4
Channel Id: undefined
Length: 350min 47sec (21047 seconds)
Published: Fri Oct 27 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.