Build an Enterprise Nextjs Rental App | AWS, EC2, Cognito, Shadcn, RDS, S3, Node, React

68.68k views110362 WordsCopy TextShare
EdRoh
To try everything Brilliant has to offer—free—for a full 30 days, visit http://brilliant.org/EdRoh/ ...
Video Transcript:
hey guys this is Ed row today we're building a scalable nextjs real estate application from scratch this isn't just any application it's a fully featured Enterprise grade rental apartment application with the nextjs front end no JS backend and fully deployed on AWS before we dive in let me show you a quick demo of what we are building all right so here we have a pretty good looking website for a landing page for a rental application we have some animations that come in to show a nice landing page but more importantly we have in sign in
and sign up buttons so we're going to sign up for an account and we are going to be greeted with username email password confirm password and the role whether we want tenant or manager and depending on your role you're going to have different sets of dashboards so let's fill this out and then we're going to hit create account and it's going to say they emailed you your code is on the way to log in enter the code so I'm going to go on my email I'm doing it on the different screens so you won't be
able to see but we are going to add our confirmation code and we're going to hit confirm once we are confirmed we're going to be logged in to this page most of it is still going to be the same but we have our user now that we can go to the dashboard but before we go to the dashboard we're going to go to our slash search page so in this/ search page we're going to be able to see a very nice looking map so this is where we're going to be able to search a bunch
of properties depending on the location for example this is is set to Los Angeles so in this location we only have eight properties but that's part of the mock data but you can put as many properties as you want and then this will be completely fully featured we can filter the locations via the price for something like this like less than 2K so now we only have four properties we can also filter by beds and also bath to go to rooms and tiny house and the map changes and it's a very nice looking custom map
and then on top of this we also have in all filters bar that we can extend the filtering function even more it's going to include price range with a slider we're going to have property types any bed any bath square foot and also date we can also do all of that and we can even reset filters so we go back to our original and it's very nice looking and the map is quite responsive we're going to be using map box which is much more Enterprise grade map utility because you can customize this to your own
needs way more than any of the Alternatives like Google or react leaflet this is just a lot better and this is what a lot of Enterprise companies use if they have very heavy map uh needs but it is also free by the way free for to an extent of the amount of API calls but we'll get into that on top of all this these properties that you see here this is getting filtered through server side which is a lot harder than doing client side now I will talk about the difference between both of those but
this is much more Enterprise level way of filtering and it's good for large applications so on top of here we can also fil favorite or unfavorite because this user is already logged in you can favorite or not depending on whether they like that apartment and then from here we're going to hit this button for any one of these apartments and then we're going to be able to see an individual page for the apartments or the rental location and we'll also be able to see again the mapbox uh image of where it is located and all
of this is using actual information from the back end all right so from here we can even go to our dashboard as you can see we have favored properties for this user so we have favored properties and you can see the details of the favorite properties with a lot of information about their leases the payment method and their billing history and then from here we can even go to our residences so these are the residen residences that the user is logged into or basically has a lease with the apartment and we also go to settings
and we can actually see the name email and phone number and we can edit and even change their name over here let's just add something like this we can hit save change and we can see that that we have a little nice notification saying that the setting has been updated successfully I can refresh the page and see that it's been changed and then over here we also have applications these applications include a bunch of applications that the user has applied and if you saw the previous page where we saw the apartments we can actually create
applications as well if we go over here click on one of these and we hit submit application you can fill all of this information out and submit the application and it will pop up in this application section and it will show whether the application is pending approval or whether it's been denied so all of this will be fully functional on top of this we also have a little nice uh UI dashboard with a little sidebar that adjusts based on whether you click it or responsive to the size of the screen and this is using Shad
CN sidebar so that is a very new component that shad has and it's actually quite nice to use so this represents the user who is a tenant but we also have even more pages for managers managers have a different set of pages so it's slightly different they're kind of similar but they have slight different functionalities and let me show you what how those look so I'm going to hit sign out and I can hit sign in and log in as my manager account so once I have it there I'm going to sign in and then
now I can go to dashboard so inside our dashboard we also have a test property which we created a new property but basically we have the properties list which is associated with this particular manager and all of this data is connected through SQL databases has relations so it's very Enterprise level and also these are the applications but this is the applications for the properties that the manager owns so the applications that the tenant submits if they submit MIT to the property that the manager owns he receives that application and we have different functionality depending on
whether it's been denied or if it has been approved you can contact the user things like that so it's a lot of different um functionality for all of this you can also have settings and change their uh settings information as well up to you and we also have properties we can go over here and we can click on one of these properties and you'll be able to see who which tenants are in that particular apartment and there's that and then finally we can add new property which is a very detailed uh form over here we're
going to have all of this information and you can be able to create property as you can see I have this test property I didn't add any images but this test property will show you um an example of adding a new property and as you can expect with most my applications they are pretty much fully respond responsive for every single page of this application on top of building the application I have in a mirror document provided a lot of description and details for your better understanding so we have the app mop designs that are in
the miror application then we also have the ER The Entity relational diagrams for all the backend database information needs and we also have off screen flows that describe how authentication and hogo will work and then we'll also have a description of how the property search works because that's pretty complicated and then a description of all the flow managing of how the applications or leases locations things like that work and then we also even have AWS Cloud architecture so we're going to go through all of this as well and also the difference between client side server
side as well as some brief primer on CER ranges so all of this documentation is available on mirror documentation and it'll all be in the links below as part of this application for this application for the front end we're going to use nextjs for its powerful server side rendering and routing we're going to manage state with Redux toolkit Style with Tailwind CSS and Shad CN add typescript for type safety we also include framer motion for animations react hook form for forms and Zod for validation for the back end we're going to use node.js with expressjs
to create a scalable API we're not relying on managed services like aight or convex because building a custom backend is going to give you full control over scalability and cost efficiency skills that are very critical for Enterprise level companies companies are not going to want to pay the high cost of aight or convex when you start scaling up we're going to deploy on AWS ec2 which is AWS scalable compute service API Gateway to secure our route request we're going to use RDS for database scalable relational storage for file storage we're going to use S3 for
our images and we're going to use AWS amplifi to deploy our front-end nextjs application easily I'm going to break this all down step by step so don't worry I'm going to make it easy to follow even if you're new to AWS and also we're going to integrate AWS Cognito for secure authentication making this app ready for real world use so just to reiterate in today's job market knowing how to build scalable systems going to set you apart as a developer AWS is the gold standard for cloud infrastructure regardless of whatever anyone says it's still going
going to be used by large companies and mastering it will give you a huge Edge in your developer career and having said that about AWS building this app has been a rewarding challenge creating Enterprise applications requires critical thinking problem solving and learning new skills every step of the way it's all about learning by doing that's why I'm excited to talk about today's sponsor brilliant brilliant is a platform where you learn by doing with thousands of interactive lessons in math data analysis programming and AI what I love most about brilliant is how it's designed to actually
help you understand Concepts not just memorize them their Hands-On problem solving approach is proven to be six times more effective than just watching lecture videos and as someone who's always looking to level up my skills I really appreciate how brilliant helps me build real knowledge in just minutes a day it's the opposite of mindless scrolling brilliant has a ton of new content like their data science courses where you can work with real world data sets from companies like Airbnb and Spotify or if you're into Pro programming they've got courses that teach you Python and even
how to think like a programmer it's perfect for anyone who wants to turn curiosity into Real World skills so right now you can try everything brilliant has to offer for free for 30 days by visiting brilliant.org Ed row or clicking the link in the description plus you'll get 20% off in annual premium subscription if you're looking up to level your skills this is the place to do it and it can be a game changer for sharpening those problem solving skills all right let's get back to building our application as always I designed this application myself
so you're free to use parts or even the entire project for your portfolio so let's dive in and start building so the first thing we're going to be doing is we're going to be installing node.js so nodejs is a servide JavaScript runtime built on the Google Chrome V8 JavaScript engine basically means that you can run JavaScript code on your computer so go to the link in the description and you can install nodejs and then from here we're going to be installing npx so npx will help us install some npm package binaries so if you go
to the link in the description you can run npm install DG MPX and then for our text editor we can use Visual Studio code I'd probably recommend this text code editor but you can use other options if you want to use those all right so from here we're going to open up VSS code and you're going to see the interface like this and we're going to open up our terminal by hitting control apostrophe and you're going to see the terminal open up like this and in side here I'm going to write MPX create-- apppp at
latest and you might see a question before this just hit why so you'll accept it and we're going to create a project called real-estate we're going to hit yes for eslint for Tailwind for Source directory yes for app r no for Turbo pack no for import Alias so all the defaults basically then from here you can open up the explore see that we have a folder called real estate from here we're just going to right click and rename we're going to call this client because this is going to represent the front end all right so
from here we're going to go CD client to go into our directory and then from here before we do anything we want to go to this tab which is our extension Tab and I want you to make sure you installed es7 plus which is an extension react re Redux react native it allows you to have some boilerplate for your react code so if we just type a few letters we can get some boilerplate code for react component which will be useful and then from here you also want to install prettier CU you'll be able to
see when I save it it's going to format the code so make sure you install this and then from here if you're using Chrome or Brave you can use an extension called pesticide it allows you to see the page and uh visualize it in terms of boxes which will help for CSS and I might use it a couple times and then over here we also have Redux Dev tools which will be useful for Redux which is what we're going to be using and it'll allow us to debug Redux easily and then back to our vs
code we're going to close this out scroll this over here and inside our terminal zoom in a little bit so you can see I'm going to install some packages so I'm going to do npmi loose side react this will for icons EnV for EnV variables date functions for date functions basically react Das file Pont file Pont file Pont plugin image- exif orientation I know this is kind of long and then we have file Pond plugin image preview these are packages that will allow us to have image uploads inputs that make it quite easy and nice
and then framer Das motion for animation mapbox GL which is what we're going to be using a package for creating map maps using mapbox and then low dash for a few utility functions react hook- form for our forms with Zod and at hook form SL resolvers so those are for forms and validation and we are going to hit enter all right once that's complete we're going to do mpmi DD for our Dev dependencies and we're going to do at types SL node and then at types sluu ID so this is for a few typescript things
and then from here I'm going to open up the directory go to client go to source and we're going to go to page. TSX I'm going to close so there's more space and what I'm going to do is go over here where you see all of this inside our div and we're just going to delete it erase the class names as well and I'm just going to write home over here erase this image and then just save it and then from here I'm going to run npm run Dev to run our nextjs application just to
check that everyone works as expected and you can go over here Local Host 300 000 you can do control click and open it up and if you open it up and you see home over here with local hose 3000 that means everything is working as expected and then from here we're going to be installing a few things for tailwind and chaten so for extensions I want to go to Tailwind CSS intellisense and this intellisense allows us to while we write it will show us the possible Tailwind classes that we can use use which will make
it a lot easier and then also if you want this is optional you can use Tailwind documentation I personally use this one which allows you to open up Tailwind documentation by clicking this button and the Tailwind documentation will pop up on the right but this is entirely optional you can just go to the documentation on the website of Tailwind if you want then from here I'm going to close this out close this directory and I'm going to open up terminal I'm going to turn off our server by hitting control C and I'm going to type
MPX Shad CN at latest andit dasd like so this will initialize our Shad CN so we can install the components and we're going to hit Y and over here we're going to do use Legacy pure dependency because of react 19 and chadan not being completely updated due and then from here we're going to install all the Shaden components that we're going to be using and it's going to be quite a bit so just bear with with me we're going to do npx Shad CN at latest add Avatar badge button card checkbox command dialogue dropdown-menu make
sure you spell that correctly form input label navigation dmenu radio-group select separator sheet sidebar skeleton slider center switch table tabs text area and Tool tip I know it's quite a bit but if you need it you can pause it just make sure you write all of those and again you're going to see this so we're going to do use- Legacy dasp dependencies and with that if you open up our directory once again you're going to see a components folder and you should be able to see all the components that you have inside here as well
as a new file called components. Json that will configure Shaden for us all right then from here we're going to install react Redux and Redux toolkit which is what we'll be using so we're going to do npmi react-redux at Redux JS toolkit. EnV and we're also going to write-- Legacy DP DS or else it won't work properly now again I just want to explain why I use Redux toolkit over something like zustand but cuz Redux is much more Enterprise focused it is a much more scalable and robust toolkit over something like zustand people talk about
the boilerplate in Redux even Redux toolkit but all you have to do is copy paste one or two files and you're you're already set you can reuse it over over and over and it's super easy to do so having said that the file that you want to copy we're going to grab it in the asset download folder that I have in the link in the description that's going to include a lot of files that will make the whole entire coding process for this entire video much less tedious and less involved so I want you to
make sure you download that and I want you to unzip that zip file and we're going to make sure you paste it in over here or drag it into this directory so we have asset download right above our client so you should have something like this and we're going to go into our client and you're going to see a number of files so we're going to be dragging and dropping a lot of these files into our client directory and it should make our lives easier so the first thing is going to be this global. CSS
so it's going to replace the one that we already have because this will include some stat fing that will make it easier so we don't have to deal with that so I want to drag it replace it and it should be good and over here we're going to also go over to our client directory and replace Tailwind doc config.txt config.js cuz there's a few things that I changed it's not too much but it's just a few files that will make it easier for us to use typescript and then from here we're just going to drag
both hooks libraries as well into our source directory so I'm going to grab these two and actually in postproduction I remov the hooks folder you don't need to replace it because it's already here so we're going to keep that but for lib I want you to grab all of this and we're just going to replace the lib folder cuz it's going to have a few extra files all the constants and all the schemas and utils this will make our lives a lot easier when we're writing the code and then finally we're going to have the
state directory so this is going to include all the Redux uh boiler plate that we need to set up our project and I can tell you this is all we need to do every single time we set up Redux it is not that much it is code that you can literally copy and paste every single time if you ever wanted to make some changes you can but this is basically the root of everything we need for our Redux toolkit and the API file is where we are going to write our API calls and the index
file is if you want just use Redux Global State I'll cover there's one last thing we need to do with Redux but it will be pretty simple the other thing we need to drag is the types so this already has a lot of the types that we're going to using I feel it's not very productive to use these types when we're doing the application so we're just going to drag that in for now and then finally with our public we're just going to go and have all of these images that I've already added we're going
to go and replace the public folder in our client directory and then from here we can finally delete our client app we're just going to leave the server for now and we're going to be dealing with that later so this should set up most of everything we want and then from here we're going to open up our directory or open up our terminal in client and I'm going to run npn run Dev just to make sure everything is still working and if you do this you're going to see a homepage this time it's going to
be a white page over here so this should be exactly what you expect I did mention one thing we need to do for our Redux setup is just for more cleanliness we're going to going to go to app we're going to create a new file we're going to call this providers. TSX this is for any app or for any libraries that need some kind of Provider that need we need to wrap the entire layout for so we're just going to have this as a separate file and we're just going to write this out we're going
to do use client colon like this and we are going to do import store provider and we're going to use the intellisense this is very useful when it pops up you can just click on it and it's going to write by doing so it prevents bugs when you do that it'll make our lives a lot easier because we don't have to write all that code and then from here I'm going to do const providers like this and we're going to pass in children like this colon children colon react. react node like so and we're going
to do an arrow function like this and over here we're going to do return and we are going to Pro do store provider like this and make sure we close it and pass in children and finally we're going to do export default providers so this separate file will allow us to write a bunch of providers and this is actually necessary for nextjs anytime you use providers so it's not redu specific it is specific to anything that requires provider around the entire application so that when we have these providers we can go to lay and we
can go down over here right around children and we are going to do providers and pass in the children inside the providers and make sure we import this so what I did was just erase the s or the last letter and rewrite it so the intellisense pops up so we can just import providers that we just created and we're going to save it and just to double check for good measure we're just going to make sure everything works as expected if you get no errors that means you did this correctly and our Redux is basically
set up and once again with Redux if you go to state you can tell that both API and the global state is set up with just these three files you just need these three files and set it up around the provider and then you have everything set up a lot of people don't realize when you use something like zustand you still have to set up react query you have to configure it with zustand and you have to make sure you have to create your own extractions around it to get same levels of functionality where it's
built-in Redux toolkit it is a tradeoff but the boiler plate in Redux toolkit is not that bad at all whatsoever they are about the same I would say Redux toolkit has a little more boiler plate but it is better for Enterprise zustan has less boiler plate but it does have issues when you come to Enterprise level this has been my experience I have talked to people who have used zustand and it seems like a common experience that's my rant don't just always trust these influencers who always tell you to just use the latest newest thing
Enterprise level when it comes to it it is is really annoying to use new Tools in Enterprise settings because you may run into an edge case that the person who created the library has never encountered before all right from here I'm going to close this state up I'm going to close all of this over here I'm going to make sure I have the app running just in case and over here in our app directory I'm going to create another folder I'm going to call this non dashboard in parentheses and the reason why I do nonp
parenthesis if you don't know in nextjs if you do parenthesis it is not included in the route so if I created a new folder I call this non dashboard like this and I created a file called page. TSX that means if I wanted to go to this route right here I would do Local Host colon 3000n dashboard that's how you get to this particular component page that's how routing works but if you set it up with non dashboard that means this is not going to be used in the route and we're just going to put
and group everything between non- dashboard versus dashboard because that involves what is behind authentication versus non-authenticated Pages or things that traditionally look like a dashboard so in our non- dashboard we're going to create a new folder and we're going to call this land in so in our Landing is going to be where we have our main landing page which looks like this so this is our completed application this is what we're going to be creating and we're going to divide this up into separate parts of the application we're going to start with this Navar this
main page this section this section this section and the footer as well so those are going to be separate sections and we want to start with our nav bar so over here I'm going to create a new file I'm going to call this page do page. TSX like so and page. TSX is how you can have that component on that particular page this is how you have the routing so if you do slash Landing you're going to go to this page so we are going to use our extension we installed earlier we're going to do
R RAF CE and that will automatically give us spiler plate which makes it super easy and we're just going to write landing and to see this in action we're going to save that go back to Local Host 3000 you're not going to see anything different here but if you do slash Landing you're going to see that we have Landing text over here even though it's a little bit small now we could put a nav bar here but we are going to have multiple Pages for our non- dashboard section and we want the nav bar to
be the same for all of those so in our n non dashboard I'm going to create a new file called layout. TSX so basically any folder if you want them to have the same layout like basically a template such as the nav bar which gets reused and maybe the further if you want to use that too this is how you can do it this one is global so this will be applied everywhere this is specific to this folder so we're going to write rafc once again this will be layout like so and in here I'm
going to remove the layout and I'm going to do nav bar like this which we have not created and we're also going to add main class name like this and we are going to add some classes we're going to add H full Flex with full Flex column now I'm not going to go over a lot of this while I type this out because I don't know how useful it is but just understand these are Tailwind classes for example this is a full height this is flex boox this is with full and this is flex column
so these are things that you should could probably look it up if you need to but these are just ways to style It Anyways inside here we're going to do padding top with with a constant of Navar height which we have defined in our Libs constant which is something we created or passed in earlier and we're going to do and I'm going to close this main tag and pass in children like so and that children should be over here we can actually go to to layout and we actually go to Providers and we're just going
to copy this part right here with the children and we're going to paste it over here because it's the same now I'm going to comment that out and I'm going to say a nav bar like this just to see how it looks like so by doing so we can see we have Navar on the top with Landing component underneath so that means that this layout is included with the template for this Landing page basically it helps us reduce code if we're just for example reusing navbar in multiple places but with that let's remove the navbar
text uncomment the Navar component and we are going to create a component called navbar within our components directory inside our components directory and not under UI because we're going to reserve that for shaten so we're going to create a new file we're going to call this nav bar bar. TSX over here and we are going to do rafc once again put Navar and we're going to make sure we import it over here by closing or erasing the last letter and retyping it we're going to save that and we should be able to see we still
have Navar but this time is capitalized so you can see that we made changes all right so we're going to go back to our navbar component and inside here I'm going to write some class names I'm going to do class name like this with fixed top- z left- z with the width of full Z of 50 to make sure it's on the front and Shadow XL so this will basically position the nav bar on the top with some shadows and also we also want to do style to be the height to make sure our Navar
is very consistent we want to have the constant of navbar height in pixels and by the way Navar height is in 44 uh pixels high and by the way when I save it it's automatically um code formats that's the work of prettier so make sure you have that insection and Sal so back over here we're going to do div with the class name of flex justify between so everything space between with items center with the width of full py of 3 PX of 8 background of primary 700 so so this is a color that we
have set in our Tailwind config if you go back I just wanted to show you primary 700 is colors I have set for this particular application and you want to always make sure you have some kind of set of codes of color that you were going to use and but the text is just going to be white like that we're going to close the div and inside here we're going to do another div to make sure we are going to deal with the left side this time we're going to do items center with a gap
of four and for uh desktop and responsive purposes we're going to do a gap of six for larger device and by the way the reason why we're doing it if you take a look at the final application this includes this Flex box so you can click on uh pesticide and this entire one is flexed but there's also Flex for these there's also Flex for these and as well over here so that's how you can see what's happening and over here for the navigation we want this to be a link so we're going to use next
link for this which is going to take in a hre and we are going to set this to be the homepage so if you ever are on other Pages you want to click on this link which is the logo that takes you to the homepage which is by a default thing for pretty much most apps and over here we want to make make sure a cursor of pointer and hover and we can do this exclamation which is means a important tag in CSS to make sure it it changes the color properly and we are going
to set this to be Scroll of false because there's a warning that issues if you go to a page and it has some scrolling issues it's going to take you to like a specific section on that page for scrolling purposes initially this is to make sure you don't get those problems because sometimes if you use fck fixed you're going to have issues with that especially in next so over here we're going to do div pass in another class name we're going to do Flex with items D Center and a gap of three we're going to
close that and we are going to pass in image tag over here from next like so and I'm going to close this out but I'm going to pass in source and we are going to pass in the logo. SVG alt is going to be renti which is the name of our application logo to make sure that people who have screen readers they can read this with a width of 24 a height of 24 class name with the width of six height of six like so and inside here we're also going to have div with the
class name of text being extra large and font of bold for the the app name so we're going to do rent like so and we are going to pass in a span so that we have a class name with a different set of text styling for the second part of the word so we're going to do secondary d500 font DL so lighter font and also text of primary 300 when you hover over it and we are going to say iful and save it so we can see what happens over here we can see that we
have renti and if you hover over it the text gets a little grade over it when you do it by the way I moved it over here so it's easier to see and then below this link we're going to do a P tag we're going to do class name of text primary D200 we're going to make sure it's hidden on small screen but it is visible on larger screens so that was MD is doing and we're going to say discover your perfect rental apartment with our advanced search so I'm going to save that and you
probably will see that it's not visible right now but if it's big enough you can see that it will show up and it does seem like we are at the wrong level of div so cut that out put it under the slash closing div and save it if you do that you can see that they are spaced out now which is what we want because the next thing is going to be this on the right side so for the last part we're going to do div of class name is equal to flex items Das center
with a gap of five like so close that out and we're are going to pass in another link for href SL signin which we have not created that page has not been created yet and inside here we're going to do a button and we're going to pass it in from Shad CN which isui button we're going to make sure we close that we're going to write sign in and we are going to pass in a number of properties so variant is going to be outline and then on the next line we're going to do class
name of text white border white background transparent hover is going to be background of white and hover would be text of primary 700 with a rounded corners of large and save that as you can see we have the sign in button and when you click on it you go to the SL signin page which we have not created so this is kind of what we expect now over here we need to sign up but we're just going to copy this paste it over here we're going to say sign out or sign up sorry and The
Styling will be slightly different I'm just going to erase all of this but this is going to be background secondary 600 with the hover of BG white hover of text primary 700 with the rounded large corners and instead of sign in it's going to be sign up we're going to save it and we're going to see that we have all perfect this is exactly what we want which all right so we have our Navar set up if you take a look it is very close to what we have over here so the next thing we
want is going to be this hero section over here pretty simple so we're going to go back over here close all of that out in our landing and we're just going to create a new file we're going to call this hero section. TSX and inside our page we are going to make sure actually let's put RFC over here for our hero section save it and we are just going to pass hero section from there make sure we close that and right now we're supposed to see hero section underneath here but that's cuz there was a
couple bugs that I missed so if you go back to layout we want to go over here with the div we're going to add class name of H full with a width of full like this this and instead of this padding top like so we want to add a style it should be two pns with padding top colon and we are going to copy this Navar height put template strings put pixel like so and we're going to remove this padding top as well and if you see this you'll see that there is some padding top
over here but it's not perfect now I already changed this in the asset download but right here this Navar height is 44 but it's actually 50 as well it's supposed to be 50 and that is going to be reflected in the asset downloads already because this is a a file I created and we're going to have we're going to be able to see hero section over here there's also one last thing I wanted to change is if you see this um Navar with the sign up you see the variant of outline we actually don't want
that border so we're just going to do secondary like so so that's how it should look like all right from here we're going to go to our hero section and inside our hero section we are going to add some class name we're going to say a relative with height of the full screen because we want the image to be the entire screen as big as possible so we can then import image we're going to close this and we are going to pass in a number of props we're going to do Source slash Landing DS spash
for our image which is part of the images that we already have we're going to do an alt and say rental rental platform hero section we're going to do fill to make sure the the image entirely fills the background we're going to do a class name of object Das cover object Das Center and we are going to set priority because that is the main image that will pop up we also want kind of like let's actually save this and see we already have the image and it's a pretty good size the only thing is if
we want to put text on top of it we need to add a little bit of opacity now you could bake that into the image itself which is probably more ideal if you want fully optimized but you can also do something like this where we add a dummy div on top of it we're going to do absolute inset zero which is a shortcut for top zero left zero we're going to have a background of black within background opacity of 60 so it doesn't fully darken it and we're going to save it and you're going to
see we have that little dark opacity on this image which is what we want and then from here we want to add motion dot div this is going to come from framer motion this is a way to add little slight animations from framer motion which makes it very and and we're just going to import this manually because something is not popping up we're going to do from framer Das motion like so and inside here I'm going to do initial will be an opacity of zero with a Y of 20 so it's positioned a little bit
above and we're going to animate to the Final Destination which is going to be opacity of one so that means it is visible and a y of zero that means it's moving 20 pixels from the start and it's going to fade in we're also going to have a transition which will provide a duration of 0.8 so that's the time it takes to animate and we are going to add some class settings for all the text so we're going to do absolute top one3 so that's putting placing the text at the right location we're going to
do transfer form make sure we translate it/ 12 negative and negative translate dy2 so positioned in the Middle with text Center and width of full and inside here I'm going to do div with the class name of Max with a four extra large MX Auto PX of 16 SM x 12 so different settings for different screen sizes inside here I'm going to do H1 with the class name of text five extra large font bold of text white margin bottom of four and we are going to write start your journey to find finding the perfect place
to call home some random dummy text that doesn't really matter we're going to save it and if you save it you get this error that's because right here we need to do use client because whenever you use motion frame or motion you need a client component now frame or motion provides a server component but we're not going to deal with that in this case because it'll make it a little more complicated because this one will have some interaction all right and then below this we're going to have a P tag we're going to say class
name of text extra large with text of white margin bottom of eight close this we're going to say explore our wide range of rental properties tailored to fit your lifestyle and needs and below this we're going to close this up and actually this should be within the div so right here within the div within the closing div we're going to say class name of flex justify Das Center close this out and we are going to put an input which is coming from act component UI inputs so that is from Shad CN we're going to say
type is equal to text and we're going to do value is going to be let's just say search query for now that's something we'll deal with later we're going to say on change is going to be an empty function like so because we're going to be handling that once we get to the point where we deal with some of the functionality we're going to say placeholder will be search by City neighborhood or address like this and we are going to give it a class name of width D full Max width of large rounded dnone rounded
L extra large because we need we needed to reset it and then a border of none background of white and a height of 12 and we want to make sure we do a closing tag if we save it you're going to see that we have an input over here here we have no rounded corners on this side we have rounded large extra large on the left so that is exactly what we want because that will provide us a way to add a button on the right side that will close this off this will be search
and we are going to say on click this will be again an empty Arrow function and we're going to give this a class name of background secondary five 100 with the text of white rounded dnone rounded right extra large border none hover with the background secondary of 600 and a height of 12 and as you can see we now have both our search and our search button as of right now we are not going to deal with theun functionality over here CU that just will take us to the next page but we are going to
handle that once we get to the point where we are dealing with mapbx so we have our first section set up so it is identical to the first page all right so the next thing we're going to create is going to be this part which is going to be the feature section so I'm going to open this up close all of this and we are going to go to our page and we are going to add features section like so close it and then do import features section from /features section and I'm going to create
a new file call this features section. TSX and write RF CE to have a default and we are going to save it and we should be able to see feature section at the very bottom now when you take a look at this this has a little cascading animation effect which is pretty nice so you can use framew motion for something like that so what I'm going to do is I'm going to import motion from framer motion like so and I'm going to do const container variance so we're going to create container variance we're going to
do hidden with opacity colon zero Y is 50 so this allows us to make a Cascade of animations and we are going to do visible which is going to be the end point so we're going to set opacity of one with Y of Z and the transition is going to be a duration of 0.5 which is a good timing and stagger children of 0.2 so that means there is a timing difference of each one of 0.2 seconds and in here we're going to also have item variant for each item different and we are going to
set hidden is going to give us a vity of zero with Y col 20 and we are going to do visible like so with opacity of one with Y is equal to Z like so now this will be used in motion. so what we're going to do is we're going to do motion. div same over here and we are going to say initial is going to be hidden because we labeled this to be hidden and while in view is going to represent when the element comes into the screen so that represents that the animation should
happen when we enter it and viewport is going to be once call in true so the animation only triggers once you can keep it as default which will continually trigger anytime you enter that section of the page but we're not going to do that so over here we want to set the container variance so that's why we set it up we set this up on the parent container and we also going to have to set class name so p y of 24 PX of 6 and we're going to change it for different screen sizes so
for small screens we're going to say PX of 8 large we're going to say PX of 12 extra lar we're going to say PX of 16 with the background of white and again we're going to have to set this to be use client like so so we don't get an error inside here I'm going to say div of class name of Max with four extra large Excel Max width of six Excel MX Auto inside here we're going to do motion motion and we're going to set this to be H2 and this one is going to
be variant of item variants like so and class name is going to be text 3XL font of bold text Center margin bot of 12 with a full SM colon with of 2/3 and MX Auto and inside here is going to be let me increase the space so you guys can see we are going to write quickly find the home you want using our effective search filters exclamation below this I'm going to have another div called this class name is equal to grid with grid columns one MD calling grid columns -3 with a gap of 8
LG is going to be a gap of 12 Excel is going to be a gap of 16 we're going to close this div and inside here I'm going to do 0 comma 1 comma 2 CU we're going to create three of these and we are going to make sure we have an index like so and we're going to pass in motion. div with a key of index because in react you do need to incase any list of elements with a key and we are going to set the variance to be item variants that's why we
have set those so they are staggered properly and each one has their own animations and what we're going to do is we're just going to create a separate component right below over here usually you have component one component for each file but in this case since is related this is the time where you can have multiple components in the same file we're going to do that we're going to say image source title description actually that should be lowercase link text link hre like so we're going to say colon with curly braces we're going to say
image source actually let's just copy all of this and we are going to say string like so and actually we're going to do command D for all of these and we're just going to write com uh colon string like so so we can do that all at once over here I'm going to do an arrow function inside here I'm going to have a div I'm going to give this a class name of of text Center and then inside here I'm going to have another div with class name with a padding of four rounded large margin
bot of four Flex items Center justify Das Center height of 48 we're going to close this and I'm going to do image and Pull It in from next inside here I'm going to do source with image source with width of 400 height of 400 class name of with of full h of full object contain so each one is going to have an image and we are going to do an ALT with a title so all of this will be passed in from the top and then below this div we're going to do another H3 class
name and this is for the title we're going to say text Excel font D semi bold margin bot of of two and we're going to pass in title over here and below this we're going to do a paragraph tag with class name of margin bottom four pass in description close the curly BRAC es and pass in link from next close that and we are going to pass in link text like so and inside here we're going to pass in the href for the link and have a class name with inline-block border border gray 300 rounded
px- 4 py of 2 and hover colon BJ C- 100 and this should also have a scroll equals false so we don't get any weird warnings so now this is our feature card it is not being used but we're going to go up over here in our motion. div and we're going to pass in the feature and we're going to do a closing bracket and inside here we're going to pass in image source and this should be template string SL Landing Das search and we are going to do 3 minus index dot PNG so that's
going to juuse just different images for our PNG that we have and that is going to be in the public folder that we have passed in so the images should already be there and in the curly braces we're going to do an array we're going to do trust worthy let's actually put this on the next line trustworthy and verified listings we're going to do comma pass in another string we're going to do browse rental listings with ease and simplify your rental search with Advanced and I'm going to pass in index like so for the title
so that's going to use the array and we're going to use the different string depending on the index and then we're also going to have a description and that's also going to be something similar so instead we're just going to copy all this and we can just change these Val vales instead so for the first one is going to be discover the best rental options with user reviews and ratings dot second one is going to be get access to user reviews and ratings for a better understanding of rental options Dot and the last one is
going to be find trustworthy and verified rent Al listings to ensure a hassle Das free experience Dot and below this this is going to be link text is equal to an array with Explorer comma search comma discover like so and this is also going to have an index and I'm going to copy this finally for the last part I know this is just kind of a lot of just annoying text but you just kind of have to write it normally you can just use chat GPT to write all this but we are doing this manually
so HF like that and with that let's check if if we have everything and as you can see those three come into play so we have our title coming in and then these three follow after so every 02 seconds these come and the duration of the animation of 0.5 and every item has this particular animation cycle of 20 movement of pixels and an opacity of one and there you go with the feature section and sometimes the linter is going to tell you it doesn't exist even though it does that's if you write it before before
and if you save it and rewrite it it should work all right so the next section is the Discover section this is actually quite similar so what we're going to do is we're going to go to the feature section and we are going to do command a or control a to select everything copy that and we are going to go to our Landing create a new file and call this discover section. TSX we are going to paste it and and we are going to do command D over features section called this discover section save it
and go to our page. TSX and we are going to say discover section and import it make sure we have that and then we should see a duplicate over here so we're going to start from this and then we're going to modify everything from there all right so from here we're going to go up to the Discover section we're going to open this up a little bit so we can see for this one we don't need Y is 50 we're going to remove the Y is equal to zero and the duration we're just going to
remove it item variance we're going to keep the same everything can be still there we are also going to add amount colon 0.8 so that determines how sensitive it will be once we hit the viewport so that basically means that when you go to this page when it basically triggers it triggers a little bit when you go past it that is what this amount is 0.8 is doing otherwise if you do one it's going to trigger automatically once it comes onto the screen and then from here we're going to do py of 12 we're going
to do BG of white I'm going to get rid of all of this and we are going to do dark colon actually we don't need that we can do margin bottom of 16 so for for this one we're going to say Max width of 6 XL with the extra large Max width of 7 XL MX Auto PX of 6 small PX of 8 with a large of px12 extra large of px1 16 like this and we are going to change this up with the variance or actually the variance can remain the same we're going to
change this H2 to a div and in here we're going to say class name of my of2 text- center and inside here I'm going to give this a an H2 tag with the class name of text 3 XL font semi bold leading tight text of gray 800 and and we are going to close this out and inside the H2 we are going to do discover below this is going to be a P tag make sure we close that give it a class name of margin top before text of large text of graay 5600 and the
text is going to be find your dream rental property today exclam and another P tag this time is going to have a class class name of margin top 2 text of gray 500 with the max of width of 3XL mx- AO and now I'm just going to copy and paste this because it's kind of annoying to write all of this so searching for your dream rental property has never been easier with our user oh you can use like chat GPT though right some boiler plate it doesn't really matter so we're going to just have that
and now in this case this will be a little bit different so we're just going to remove all of this we're going to do similar to before in Array but we're just going to have an array of objects we're going to do image source is colon SL Landing D ion-1 PNG with title is going to be search for properties and description is going to be browse through our extensive collection of rental properties in your desired location dot we're going to save that and then we're going to do we're going to take this copy it two
more times and we're just going to make slight adjustments for each one so the first one is going to be calendar the second one is book your rental and your description is going to be once you've found the perfect rental property easily book it online with just a few clicks dot make sure you spell that correctly and over here we're going to have heart and we are going to say Enjoy your new home and your description is going to me move into your new rental property and start enjoying your dream home and below this we
are going to map all of this out so we can pass it like we did before with the card and we are just going to in here create a motion. div with a key of index and a variance of item variant like so and in here is going to be another component which we will do this will be called Discover card instead but this time we don't need link text or link hre we're just going to have a source title and a description everything can remain the same over here and in this we are going
to do PX of 4 py of 12 Shadow large rounded large background of primary 50 and MD of height 72 I'm going to erase these class names as well we're going to do BG primary 700 b or p is going to be 0 or Dash 0.6 R if you ever want a hard code this is how you do it instead of using the normal padding and then we're going to do rounded full margin bottom of four each of 10 width of 10 MX of Auto for these ones are going to be small so we're going
to do width and height of 30 we can keep all of this the same except object contain we can leave that away we're just going to replace these class names we're going to say margin top of four text Excel font medium text Gray 800 and we're going to keep it like that and finally for our PEX tag we're going to have margin top of two text of Base text of gray 500 and we can just remove this link in above here in the motion. div now we can just do Discover card and we can pass
in the card like so so that basically passes in all of this and this actually should be yeah yeah I messed this up so we're going to do Discover Card dot dot card like so and we are going to save and once you have that you should be able to see we have our Discover card and it does seem we are missing a text Center for some of these so if you go over here we can add maybe text Center like so and everything will be centered so that is our Discover section and we do
have a warning over here so just remove that import all right so the next part is going to be this call to action page which will be pretty simple so we're going to close all of these we're going to go to page to Landing create a new file we're going to call this call to action section. TSX and inside here I'm going to do RAF C we'll have the call to action all set up and inside here we're going to do a div we're going to do class name of relative with a pi py of
24 we're doing relative because anytime you have an image and you want to put something on top of the image which is like these text then you set the parent container to be relative and inside there we can have an image which will represent the background and then another one that's going to be the absolute on top so I will demonstrate this so image is going to be inut orted we're going to have a source of SL Landing d-2 action. jpeg like so we're going to have an alt and we're going to say rental search
section background we're going to have a fill with class oops class name of object D cover and object D Center so we Center the image and and we want to make sure everything is covered and we also actually we don't need to set priority because it's not the first image that will be displayed so we're going to do div with the class name of absolute like we did before we're going to do inset zero as this will represent the dark background opacity and we are going to do BG opacity -60 and we are going to
close that and you can see see that we have nothing to show for it that's because we haven't imported here yet so we're going to do call to action section add that in and we should be able to see an image and as of right now you it's kind of cut off this is all we can see but once we add the text we should be able to see it so let's continue and we are going to do motion. div once again so when we import motion it should be from framer motion and we also
need to do use client and inside here we're going to set the initial to be an opacity of Z with Y of 20 with a transition period of duration of 0.5 and we're going to set while in view is going to be opacity of one with Y of colon zero we're going to set viewport is equal to Once colon true and below this this is going to be a class name of relative Max width of 4 XL with extra large Max width of 6 XL MX Auto PX of 6 small screens PX of 8 LG
px2 Excel px1 16 this is all for responsive and py of 12 I know it's quite a l lot but it helps for us to do responsive all right and then for our text we're going to do div with the class name of flex Flex column MD Flex row justify Das between with items Das Center we're going to close that and inside here I'm going to do div of class name of margin bot of six MD of mb0 MD of margin right of 10 and inside here I'm going to do H2 class name text 2XL
font Das bold text of white and we are just going to do find your dream rental property and we should be able to see there's the text actually this should be capitalized and below the closing div we're going to add another div and inside here we're going to do a P tag with class name with text of white margin bottom of three close that out and we're going to say discover a wide range of rental properties in your desired location and below this we're going to have another div do class name with flex justify D
Center and for larger screens we're going to do justify Das start for responsive and we're also going to set the button to be search and inside here I'm going to set on click and we we going to do window. Scroll 2 top colon 0 behavior is going to be smooth so what this is going to do is just going to take you to the search uh search input that we already created earlier and I'll show you I'll demonstrate this once I create this so we're going to have a class name with inline-block text of primary
-700 bgf white rounded large PX of 6 py of3 font D semi Boldt hover BG primary 500 and finally hover text primary of 50 and below this we're going to have a link I'm going to close that we're just going to say say sign up and inside R link I'm going to do href is equal to slash sign up with class name is going to be inline-block text of white background secondary of 500 rounded large PX of 6 py of three font D semi bold hover BG hover colon BG secondary 600 and on the next
line I'm going to do scroll is equal to false and make sure we import the link and as you can see we have both search and sign up if I refresh it you can see it all of that pops up and if I hit search it's going to go to the top and it's a very smooth scrolling to the top kind of cool that it's very native now and last but not least we're going to do this little footer section it's just a nice little CSS challenge but it's not that difficult we're just going to
go to landing page we're just going to do F section. TSX and we are going to do RAF CE put the F section import it over here F section make sure we close that so we can have our Foo section at the bottom as you can see at the very very bottom you can see the F section and I forgot to mention for these icons these are not blose side react so we're actually going to have to install this we're going to close this out so we're going to do mpmi Fort awesome slash font awesome
slash or DH SVG dcore at Fort awesom slf free Brands - SVG D icons and at Fort awesome SL react Das font awesome because lucide react doesn't support it anymore for and if we get that issue I'm just going to hit up so we get the same thing and we want to do - Legacy Das Pier DS and this is because of react 19 they just don't have the support for it so we're just going to do that and make sure we run it again and I'm going to close the terminal and we can start
writing our code so over here instead of the div we're going to do a f inside the fur I'm going to give this a class name of a border T border gray of 200 with a py of 20 inside here I'm going to have another div with class name Max with a 4 XL MX Auto PX of 6 SM colon PX of 8 close that out and inside here we're going to have another div we're going to say class name is equal to Flex Flex DC column MD of flex D row with justify Das between
items Das Center and I'm going to close that out we're going to have another div with class name of margin bottom of four close this and we are going to create another link pass the link in with hre Slash class name with text of excel font dasb scroll is going to be false and we are going to pass in rent to full and we're going to save that let me get rid of this further section and make sure we are seeing it on our screen and I need to refresh this page and we should be
able to see that the rent link is there now below this div we're going to have a nav element and we're going to do class name of margin bottom of four we're going to have a unordered list we're going to say class name is equal to flex space of X of six so everything is spaced out we're going to have list item and it's going to be a link with href of slab and we are going to do about us and I'm just going to copy and paste this multiple times and I'm just going to
say contact us with FAQ terms oops terms like this with privacy like this and make sure we change the link now a lot of this is just going to be dummy links these don't really take you but if you ever want to really create your pages out you can do this we're just not going to get into it because it's not very useful to learn and so from here we're going to do a div we're going to do class name again with flex space between of four so basically that does Gap by the way this
this just gives us an easy way to do a gap between items and over here we're going to set our brand icon links so we're going to do hashtag like that with aria-label is equal to Facebook class name is going to be hover colon text- primary 600 and inside here we can do font [Music] awesome icon is going to be icon is equal to fa Facebook class name of H6 with 6 and we're going to close this now for this we're going to have to import this manually because it's not popping up so we're going
to do font awesome icon from at Fort awesome and we want to choose the last one react SL font awesome and we're going to do import fa face book fa Instagram fa fa Twitter fa Linked In actually this should be lowercase fa YouTube and we're all going to grab that from at Fort awesome and we are going to do free Brands SVG icons so once we have that we can scroll down to see these in action so we're going to just going to copy this paste it over here I think four times we're going to
change this Facebook to be Instagram this is going to be fa Instagram like so this next one is going to be Twitter so this is going to be Twitter change this to Twitter as well change this one to be linked in and actually I'm going to copy this paste it one more time change the LinkedIn to be YouTube for both of them take a look we have our brand icons and that's pretty nice and finally we just have one few more things and we'll be done for the front end for the time being text Center
text small text Gray 500 so we're going to have Flex justify Das Center space of x-4 close this off we're going to give this a spam and if you want the copyright tag you're just going to have to search it up on Google copy that paste it in there and you can do rent rent to full like so all rights reserved and then from here I'm going to do another link we're going to say href slash privacy privacy policy and I'm going to copy this two more times this is going to be terms of service
and this one's going to be cookie policy so I'm going to change this to terms and cookies now these are all dummy links nothing too important but just if you wanted to do a real application you can add all those links and do what you need and there you go that is the landing page it's a lot of front-end kind of you know run- in-the-middle type front-end stuff but we are going to do the juicy stuff which is the backend next now with that our landing page is fully complete the next step is going to
be doing the back end and the first thing you want to do with any backend is actually set up the data model so in the link in the description there's going to be a link to this mirror board which has a lot of diagrams it has the designs if you want to take a look by the way it's not fully 100% accurate on what you see in this final application but it should be pretty close and there's some other diagrams that we'll cover later but the main one we want to talk about is this entity
relationship diagram and database so basically this is just another way of organizing our database and our backend so that all our data is properly organized because if you don't do this process like I mentioned many times in all my videos if you don't do this process very well and organize your data correctly all your other code everything Downstream including frontend is all going to be a lot Messier so you do have to think about this quite a bit and it's important to identify when you're dealing with something like this all the different entities and you
want to think about it in more a common sense mindset for example property is an entity that you want to create in your database as well as application lease payment tenant things of that nature that represent a real physical data type object this is very important to do that and making sure you have the correct property now this application is using postgress and SQL now you could could use Dynamo DB but for this application we are using location data meaning this is going to have geography information you could store location information inside a Dynamo database
or a nosql database but the most optimal solution for any kind of geography location would generally be using postget with something called postgis and this is for situations where you have like a real estate where you're on a certain map and let's take a look at our application if you go to the slash search page over here you can see we have a list of map when you are fetching a list of items for a specific map it is easy to get the locations all at once using postgress postgis there's other alternative options using nosql
but postgis is optimal for something like this because you're dealing with heavy complex filters which we are going to cover there's going to be a lot of filters in this application so we are going to be using post Gis for this now going back also for SQL a lot of this is pretty self-explanatory the main one we are going to cover is going to be property that's going to have lots of information and this will represent the property object and everything most of everything will be connected Ed to it including applications are linked to property
as well as to the tenant and we also have a tenant versus a manager because a lot of times when you have different user roles you want to store that information separately and then finally we have both a lease and a payment table these won't we were not actually going to do Payment Processing but we are just going to store this payment and lease information and we're just going to fetch them together using using SQL queries and finally it's not shown here but there's a reason why we store user information manager and tenant even though
the authentication that we're going to be using is Cognito Cognito is going to store important security information like the password email things of that nature is going to be stored in cognito but we need to make a copy of it in our manager and tenant otherwise we we we need an entity so that we can connect it to the rest of the application so we actually need both a tenant user data item for example and also a data item Incognito where it stores it on AWS so you basically need two different duplicate items that represent
the same user and the way we connect tenant to the Cognito is this item right here with Cognito ID it is an important it is very important to understand how that works and we'll cover authentication when we get to it but this is the basically data model this one should be pretty straightforward to look at not too complicated in terms of things but it should make a lot of sense and that's exactly what you want the data model and the data schema should look quite similar to this now there is really no wrong or right
way but a lot of times you just want to be able to optimize for the ideal scenario which is when you make a call for properties for example in this application when you are doing something like system design you want to be able to optimize this page because most people are probably going to be using this page as this is where users don't even have to sign up for like in the real estate application this is where you want to be able to grab all the properties and all their locations in one go so you
always want to make your data model skewed favored towards something like that so having a property and also a location will be ideal for both of but that's pretty much it we'll talk more in detail of all these properties as we go but that's pretty much everything we know about the database so the next step is kind of the part where it gets kind of annoying it could be very easy or it could be kind of annoying depending on your computer and whether you might run into some issues which is the installation of postgress now
the postgress we are going to use when we deploy the application will be used on AWS but we want to be able to run our database locally before we do such a thing so there are a couple things you need to install so the first thing is going to be postgress postgressql so over here there's a link in the description where you can download this you can choose Linux Macs OS and all of the install installer will be there and when you install this there's also going to be something called postgis and I have another
link showing postgis installation that will show you while you install for Microsoft Windows there's going to be a spatial extension saying post GIS you want to make sure that's checked off same thing with Apple Mac OS you're going to have something like this when you're using the installer version so when you're going over here you want to make sure you install the correct download for example in Mac it's going to show you how to install it over here there is an installer which is what I would recommend that makes it easy it goes through the
steps and processes of installing it you want to make sure you want to download the installer otherwise if you want to try your own way you can install it manually using some other things like here now I I've already installed this but I'm going to give you some screenshots of how the installation should look like I think I have majority of the screenshots but I don't think I have everything but there are a couple things I want you to note so this is a Mac version so make sure if you're doing Windows it should be
slightly different but you should have all of this you want the stack Builder as well as well as the command line tools make sure everything is checked and this password right here is going to ask you as well as a super user you want to make sure you have the super user set to postgress so make sure you have the user super user written down as well as the password that you put in my case I put 1 2 3 4 and that's what I'm going to refer this password to if you don't have these
passwords uh written down you're going to run into some issues later on if you don't have those it's going to be a pain to fix so make sure you write those down keep those in your back pocket so that we can use them later for PG admin and from there you can see select the port number I want you to use 5432 but you can use whatever you want but make sure you note this as well it's important and over here oh sorry you can go over here you can do default local doesn't matter and
the following settings is just going to show you the summary and over here we're going to choose in my case I had postes 15 but you probably have postest 16 and you going to choose the 5432 make sure you have that and make sure you have the stack Builder and this is where you install post GIS this needs to be installed for us to use the geography stuff so you're going to have that I just put in the download directory and you're just going to have this agree so that should be good now when you
finish installing it it's probably going to be running the postgress qo but sometimes sometimes the postgress app is not going to be running maybe you restarted your computer and it turned off something like that I just want you to know that there's a way to restart the postgress and if you're using Mac it's something like this is the location which is Library postresql 16 bin and then pgct so you double click this and it's going to start the application and if you if you don't want to go all the way in there you can bring
up your terminal and you can write the pathway for that path and you can write something like this this is how you start your application and sometimes if you have admin issues you are also going to have to use and if you have admin issues you're just going to write this as well for this is only for Mac specific but that's only if you have permission issues but this is how you start the application you're going to always have to start that to make sure your database is running correctly sometimes as you can see is
it cannot start server because the server is already running on my end so it just depends if it's running and I'm not exactly sure on Windows but I'm sure the process is similar you're going to have to start the server up if it's not running all right so once you have postest installed that is postest the application but we need something to visualize what's in the postest and we can do that via PG admin so this is basically like a UI desktop version so you can look at your database and it's very archaic it looks
old and it's kind of annoying to use but this is probably the best option it has the most extensive functionality so anyways you can go to this link in the description you can go and find whichever one is relevant for you make sure you install that and I think this one is probably more straightforward I don't think they have a username for this but either way I think we're still going to use the postgress information so once you have that installed we want to open up PG admin you're most likely going to see something like
this where you have one server list and like something like this now when it comes over here it might ask you for your master user password to log in so including the password so you're going to have to make sure you have that installed now I already have one called real estate but I'm just going to create a second one because I've already built a database before I'm just going to call this real estate 2 we're going to have owner of postgress which is the super user and we're just going to keep everything default so
we're just going to hit save by the way if you don't have if you don't have a server like this sometimes you do have to register the server itself I I'm doing this a little backwards I know no but we can just use Local Host if you're registering a server let's let's just call this test I just want to show you host name address and then there's a port 5432 you want to use your main username and we we can just hit save actually we do need a password so we're going to do 1 2
3 4 and that will create our server and we'll be able to use our databases from there but I'm just going to remove this one CU I already created it but that's just the process of doing so so make sure you have that and by the way if you go over here it is really archaic as you can see the tables that we are going to set up will be in here I've already created this before so if you take a look this is the old one we have tables all the way over here and
I'll show you that when we create the database but there's also so one last thing we kind of need to do is for Real Estate we want to rightclick and hit query tool and we want to write create extension if not exist post GIS so this is for running our postgis that we installed and we want to just hit run so that will allow this database to be using postgis to make everything work work correctly and we can just save changes actually no don't save changes you can just close this and hit don't save so
hopefully you can get that installed it is one of the more annoying Parts but this is an important process of a developer if you do not know how to or you might have run into issues of issues of installation on your computer or you might have issues with others it is not easy for someone like me to determine on your computer what's happening because you might have other things installed that might cause issues or you might have a different system things all there's so many complications is is really hard for me to address it but
hopefully you can manage to get through this part is probably the biggest pain when it comes to using Enterprise level databases all right next up is creating our server and we are doing this with the separate node.js backend now I know people see oh we're going to do nextjs we're going to do front end and back end in nextjs it's a full stack application why don't we do that instead well you run into when you come to Enterprise level applications you run into issues where you're dealing with mono repo in that case because even though
you might have all your code in the front end essentially you have your backend with your front end using nextjs but in reality nextjs is still separating your front end and your back end under the the hood you just don't see it on verel now they do it with optimizations and makes it pretty fast and things of that nature but it also complicates things and they do not tell you this a lot of people say oh it's should be pretty easy but you run into a lot of weird issues a lot of more complications especially
when you're starting to use other API endpoints which have networking issues and for large companies those problems become very real and they become very problematic and I can tell you there are a lot of headaches when you use nextjs at those level and scale most people do not get to those points when they're building nextjs applications because they don't build those type of applications with nextjs but I do have a video coming up eventually with an application where we do use all those server actions and server components and I will teach you everything you need
to know including deploying on production level AWS I show you how to do that in a future video but for now we're going to keep it as simple as possible when it deals with front end versus back end so we are going to create a separate node back end and we do that by creating a new folder in our directory and we're going to call it server we're going to open up our terminal I'm going to close this out I'm going to CD dot dot to get out of the directory I'm going to CD into
our server directory that we created and I'm going to write npm AIT to initialize our npm package with Dy so that adds all the default to our package.json and if you do it correctly you're going to see a package Json in there and from here we're going to be installing a number of packages so I'm going to zoom in so you guys can see what's happening so I'm going to do mpmi let me close this out mpmi express body- parser cores. EnV helmet Morgan Json web token molter uu ID axios at terraformer wkt at AWS
SDK client S3 at AWS STK oh I did spell STK incorrectly so make sure you fix that and slash li- storage just to quickly explained Express is the framework for our backend makes apis easy to make body parser will parse our data for us for request cores will deal with cores issues. EMV with environment varibles helmet for security Morgan is for logging purposes Json web token is for our middleware for authentication we'll be using molter will be for file uploads uu IDs going to be for random IDs axios will be API calls this is going
to be for post GI is to create locations and then AWS SDK S3 so S3 as you can see and Libs storage will be useful for those and then finally we are going to install Dev dependencies so I'm going to do npmi DD Rim ra concurrently so these will be allowing us to run both the dev server and uh compile the typescript package for our application and we're going to use node modon for our Dev server SS shx for copying um some typescripts we're going to copy to the front end and then TS node for
typescript node and then typescript itself and then at types and a bunch of types typings packages for each of these so at types course at types Morgan at types node at types Json web token at types molter at types terraformer twocor wkt at types sluu ID now in a future application we're not going to install all of these because we're going to be using Hano I will I have gotten around to using Hano and I we will use that in a future application but for now we're going to keep it simple with express since it's
quite popular all right so with that installed we are going to use MPX TSC D- in so this will install and initialize typescript in our file from here we're going to go into our TSC config.js and we're going to modify a couple things so I'm going to go down to module actually string module like this where it says commonjs I'm going to change this to node node next I'm going to copy this module resolution uncomment that and paste it over here for node next and we are going to go to resolve Json module we're going
to uncomment that out we're going to go to out directory uncommon it and this needs to be disced because this will be the output of where our typescript files will go we're going to have a source directory where it's going to comp compile all the typescript and create an output of a disc folder that will be the compiled JavaScript and then finally we want to go to quotation include quotation and actually that's not written already so underneath compiler options all the way over here we are going to write include colon and in Brackets we're going
to do Source SL star starstar and then Source slata SL star starst star. Json comma Prisma SL star starstar so this is for which files to include and we want to include all the padding we will be using all right so from here I'm going to create a file or a folder in our server directory and we're going to call this source so this is where all our typescript and all the code that we'll be writing will exist in this Source directory and I'm going to create a new file I'm going to call this index.ts
so this will be the entry point for our entire application and we are going to write a lot of stuff so we are going to Let's close that out close this and we are going to import import Express from Express like so import. EnV from EnV import body parser from body- parser import cores from cores import helmet make sure we use the intelligence import Morgan from Morgan like so and I'm just going to add a comment we are going to add some route Imports we're not going to do it just yet because we have not
written the routes and in here I'm going to have a comment called configurations so these are all the configurations that start up when our Express server will run so this is just all the setup files so we need to initialize ourv with config we need to initialize Express and we are going to save that into app variable and then we use app.use express. Json invoke that then app.use helmet so we can start that as well and then we also want to do app.use helmet. crossorigin resource policy make sure we don't have cross origin problems we're
going to do policy colon cross-origin semicolon we're going to do app.use Moran common like so app.use body parser Json app.use body parser URL encoded we going to do extended colon false and then do app.use cores make sure cross origin policies works I'm going to add another comment say this is where our actual routes is going to be so we are going to do a test Home Route which is app.get comma for a slome route like that we're going to do W comma res with an arrow function we are going to do res. send this is
Home Route so essentially when you go to the path of the Home Route you're going to get this information so that will be basically a test for whether our home route Works we're going to add another comment and this will be the actual server we are going to do const Port is equal to to process. env. port and if it doesn't exist we are going to set this to be 300 and two something like that otherwise we're going to do app. listen you're going to say port with an arrow function like this and say console
log with um template strings we're going to do server running on Port and a port variable so the one thing we need for the EnV Port is going to be an EnV folder or EnV file which is going to be EnV we are going to set this to be Port is equal to 300 And1 so let's just take a look let's make sure everything is working so as of right now we do not actually have any commands so actually we can't test this so in our package. Json we are going to write a few commands
we can just remove the test I'm going to write build like so Rim Raff dist and npx TSC so Rim Raff is a command that allows us to create our disc folder and we are running typescript so it's going to compile our file for us and then also we are going to have another command for start which is just going to run mpm run build which will run this command essentially and we are going to run node dis index.js because that's the entry point for our compiled typescript files and then most importantly we're going to
have a Dev command and this one is the main one we'll be using is mpm run build and concurrently which allows us to run two commands at the same time otherwise we wouldn't be able to do so and this is crossplatform so it should work on Windows and then we are going to do MPX tsse make sure you have for slash double quote dasw double quote another slash double quotation with node Monon D- execute TS node Source SL index.ts we're going to do forward SL with double quotes like so so essentially we are running typescript
first and then we are also going to run our node server so it allow us to run these commands together all of these commands and makes it easy for us to do so and it does seem like I did make a mistake and that is with the index it should be TS make sure you have that and then this is ts- node so I had a couple typos make sure this is written correctly otherwise you're going to have some weird weird issues so I'm going to run this again mpm run Dev and with that you're
going to see that we have a dis file which has compiled all the the typescript into JavaScript over here and we should say server running on Port 3000 which looks like it is working now if you want to test the Home Route what we can do is using a command called curl you can use postmen which is something I'll talk about later but for now I'm going to do curled HTTP s/ looc host 3001 and my bad it's not https it should be HTTP and when you get that it's going to give you this is
Home Route and as you can see we have a log that says 200 at our current time and we have a get call so this is going to be working as expected which is good all right from here I'm going to close out this terminal close this out make sure we don't have the server running and I'm going to install a couple more packages so from here we're going to be installing Prisma so I'm going to do Prisma and at Prisma SL client so Prisma is a om that allows us to connect to SQL and
it writes it makes writing the code easy to make SQL queries to our database now in future videos we're going to use drizzle I encountered a lot of issues with Prisma and especially with Lambda and Prisma tends to make the file size and the bundle size of the server extremely ginormous and it is also a lot slower and setup and deployment is a big pain Prisma is one of those things where it looks good when you first start one of those situations where oh it gets you up and running and easy to read but when
you get to Enterprise level it starts to become a huge burden and a pain you know one of those things in development and then over here I'm going to do MPX Prisma init and that will initialize a Prisma file with schema. Prisma over here I'm going to close this and from here we we can now go to our asset download folder so this is where we have the assets that we already had so we already have schema. Prisma but this includes all the models that we need so if you take a look we have property
we have manager we have tenant and it has the same properties that you would see over here so all the properties we created in our data model this is to make it visualize a little easier we have it in our Prisma as you can see we have like name description things like that and all of these are like relations now you can look into it you can see what's happening Prisma is not something I will be using in the future it's caused me too many headaches so it is up to you if you want to
continue using it but either way for now we're just going to grab this Prisma folder and we're just going to drag it into our server and just replace it and that should include all the Prisma that we need as well as the seed file which is something we will use to feed mock data or fake data into our database so we have something we can show on the front end not mean to do that here is our seed data which includes a bunch of Json files and this is going to include mock data that we
can initialize into our database to make our lives a lot easier and we'll have fake data now if you want it for schema. Prisma you can go to extension you can install Prisma this adds syntax highl you can install this if you want to but since since we already have Prisma we don't really need to and then from here there's a couple commands that we want to add which is the seed command in our package Json so that we have a easy way to seed our backend database and the command is going to be seed
for the script so that will be the command that we write with TS node Prisma seed. TS basically this command will run this file and Seed our database or seed our mock data into our database and there's a couple more commands that we want to add one of them is going to be Prisma colon generate this is going to just do Prisma generate like this but we are going to use that it's a little redundant but we also are using it because we want to use post Prisma colon generate this is a way to run
a command directly after what we generate and this command is kind of interesting so what I'm doing over here is I'm using something called SS shx this will allow us crossplatform to copy a bunch of files and paste it and we're going to paste it into front end meaning once we generate the Prisma typescript which we'll we cover very soon we're going to paste it into the front end so we can use the typescript type models on the front end so that anytime we are using it in our front end we are in sync with
the Prisma back end now if that doesn't make sense I will show you why this is pretty cool so we're going to do node modules Prisma client SL index. d. TS so this will grab from Prisma index.ts which is a typescript file it will be the typescript file of all the models generated from Prisma and we are then going to paste it so this is where it's going to copy from and this second one is going to be where we are going to paste it and we are going to go to the client directory to/
Source SL types and we are going to create a file called prismat types. D.S and that's pretty much it so essentially anytime we run Prisma generate we're going to copy this into the front end so we'll always have available on the front end the typescript types that we generate from the back all right so we have all of that there is one last thing we need to do to connect to our Prisma database right now Prisma is not connected to your postgress database you know the PG admin that we saw it's not connected to that
and that's because we need to have the correct database URL I'm just going to get I'm just going to remove all of that because we don't need that but over here we are going to set the super user remember the super user I told you to write it down that's where we're going to use it and the random password is going to be the password that I mentioned 1 2 3 4 and the port is going to be 5432 which is what I recommended you to do and this my database name is going to be
real estate 2 so that is the name over here that is for the database so it's basically this name right here as you can see I'm pointing to that that is the database name this is important to get this correct otherwise you cannot connect to your database and with that we can open up our terminal and we can run the command that we identified here typically the normal command is just npm run or npx Prisma generate but we are using Prisma colon generate over here so we want to do mpm run Prisma callon generate so
it's going to do two things it's going to run generate and it's also going to do this command over here which will copy everything into Prisma types so this is pretty cool because this allows us to use the types identical to what we see in the Prisma schema so if we want to use the typescript of version of property this this is all being used in here in this code base so for example you see property application is being used let's look that up if you take a look here property is being used from our
model type so even though it doesn't show you over here this is going to have the correct property mapping that comes from a prism it's a little complicated over here if you look at it here but you can tell that it has all the right properties and it'll make sure your type safe on the front end as well so that's pretty cool we are running that command but then we are going to have to open up our terminal and we need to write MPX Prisma migrate Dev d-name init so this will initialize our migrations and
we need to reset if you see this we're just going to hit yes if you don't see it it's fine too and what you should see is this migrations folder over here and this next command could lead trouble sometimes but hopefully this works so we're going to run npm run seed so that is the command to seed our database and if you see all this and you don't get any kind of error then you're good what it's doing is clearing all the data in our database if it already exists in this case we don't have
any data so it's just cleaning out nothing otherwise we are going to to insert and Seed our data so we're going to insert locations so that's going to insert location in postgis and we're also going to seed our data from each of the files and there's something called reset sequence to 11 that allows us to make sure like IDs are properly set you don't really have to understand that but it's all in our seed file everything is happening this is something I created so it will make sure we have mock data in our database and
to double check that we can now go to our server list go to our real estate 2 for my case I'm going to hit Refresh on the tables uh you might have to refresh on your database right here as well so if you do that you can go to schemas and then go to tables and you should be able to see that we have all these models in here which is good now if you actually want to see it I know this is archaic we have a query tool actually don't don't use a query toll
we're going to do all rows for application and it should now show you all data in our database and it has a lot of information you should be able to see everything in your database which is perfect you can do the same thing make sure you hit this all rows button basically the way PG admin works is it's actually sending and creating using real SQL queries to make these fetches I know I don't really like this UI but there's no better option in my opinion I don't know maybe there is and just FYI for Prisma
if you ever run into some issues with Prisma you should write npx Prisma migrate reset and then you would run the two commands that we mentioned before which is we go all the way up here npm run Prisma generate with the colon that one make sure you do that one and then NP PX Prisma migrate Dev D- name and knit and do whatever commands it tells you to and then npm run seed so if you ever have any database issues or you change a model you might have to reset everything and this is the kind
of pain you have to deal with with a lot of databases and now with that we have everything working on our back end we're just going to do one last test we're going to run npm runev we're going to make sure it's running and there's one last thing I want to show you is that in the link of description we have Postman and this is something you can use which allows you to make API calls with the UI and it makes it easy a lot of people use this so make sure you install it and
just to show you how it works we can go over here going eras all this I'm going to do 3001 go to our home and hit send and if your server is running it should send you this is Home Route and you should also be able to see a log in your file so that should be good so you can use something like that so we have our backend fully set up now I know what we did is quite extensive and quite you know it's quite a hassle I will say there's a lot of setup
to this but once you get it it's not too bad and also I'm showing you this because you can use convex database you can use all of those backend services but this is this type of development on the back end is what you'll most likely encounter in the real World they'll have much more complex systems and they're going to be setting up with backend using Enterprise applications and Enterprise type backend Solutions and it is much more likely you'll encounter this than using seeing something like verell used for the backend entirely that is generally for smaller
applications but this is for large applications where companies might be using AWS or they might using some kind of large Cloud because their their company is just ginormous so you'll most more likely encounter stuff like this in the real world so yeah take your time to really learn this stuff this very important front end is here or there it's oversaturated but back end is generally learning it is good for your career all right so next in the steps is that we're going to start doing authentication typically I had all my AWS stuff including including Cognito
at the end of the video but I realized it makes much more sense to do Cognito in authentication early on so you have the actual user information you're also connected to con uh Cognito with the users and having all the roles as we build the application so we're going to do that earlier so in our mirror diagram there's actually another section where I describe the authentication flow I'm going to close this out and you can see that I have created a few diagrams that are pretty useful so first off let's look at the authentication diagram
so when you sign up let's say a user already signed up and the user wants to sign in once the user signs in their credentials are going to be sent to Cognito authentication in Amazon and it's going to verify if that user is who they say they are from there Cognito will send the user credentials to the client including JWT tokens session info and the Cognito user ID this part of the process is called authentication making sure the user knows and authorization is a part where it grants the user what access that they have and
that is being sent over here so that will involve more of the second part of this diagram which is when the user gets the credential and most importantly they're going to have the Cognito us user ID they're going to send the Cognito user ID and some of the user info if the user is signing up it's going to save that user into our database if the user's already signed up it's going to grab the Cognito it's going to use the Cognito user ID to grab our information from our database and in between there is something
called a Cognito authorizer this is going to happen on on API Gateway this will be like a middleman in between the client and our database to make sure the user is who they say they are so we are authenticating the user making sure they have the right credentials so that we grab the right information so that we can send it back to the user on the Cent so that is a general gist of how this essentially Works we're basically making two trips to Cognito and our database and I told you before in our database we
need to make sure we have a copy of that user in our database now if you take a look over here these are the signin and sign up pages that we are going to create in here we have the signup pages and in the signup pages will be come from the sign up navbar that we have created so essentially this sign up will take us to this page and inside here they're going to set the username email password you know the usual with a role in this case generally when you have the manager that is
dependent on the application a lot of times you won't let them be able to access manager you would have someone who has higher level access to give them manager role but in this case we're just allowing them to choose just for Simplicity sake so then they're going to create the account and again in this case it's going to go through this process with the Cognito and it's going to send the information to our database and similarly with the sign in so we also have some routing over here with the signin it's going to be this
button it's going to take us to this page and the signin button will take us to sign up here so the user can navigate in between these two pages this is very typical for log in sign in sign up and then once you hit the sign in button it will go to two different routes if the user is a tenant we are going to go to the tenants SL favorites page if not the manager properties page so the routing will be different depending on their role and I will show you how we handle that on
the frontend so this will be for this the user will be sent to this page if they're a tenant they'll be sent to this page if they're a manager all right and then finally when you hit this button this is when you are signed in you're going to see something like this there's going to be a goes to settings page and a sign out pretty standard so that should be pretty self-explanatory but enough talking let's start cracking on this issue so for Cognito the first thing we want to do is set up AWS so at
this point we're just going to go to the AWS Amazon website and AWS has a free tier but it is complicated and it is something I'll go over much later on but just know for Cognito it is always free you have 10,000 monthly active users so everything should be good so over here you're going to click complete sign up and we are going to create a new AWS account now I'm not going to do this because I already have an AWS account so make sure you go through the process verify your account and do everything
we everything in this video is going to be free for AWS at least for the free tier which is 12 months you can use everything for free and test everything out and learn as much as you want it to do but for Cognito it's always free so don't worry about that all right once you signed up and signed in we are going to be seeing this dashboard it might look a little different for you I have all of this set up and as can see my current month's cost is zero I had a charge for
cloud watch long time ago but that was my own problem from here I want you to type in the search Cognito and we're going to hit that in cognito setting it up is actually quite simple now if you take a look I already have some user pools but we're going to start from scratch so I'm going to do create user pool and over here we're going to use Spa now if you saw my other video where I did use Cognito this will this looks a little different because they updated the UI but it is a
lot simpler now not exactly sure why they changed it but they love to change things but over here we are going to rename this we're going to call this re Cognito Dasa client re stands for Real Estate I like to prefix with the name of the app just so it makes it easier for me to identify Services which for which application anyways for here we want to select email and username for signin you can do phone number but it'll make a little things a little more complicated and over here we want to set this to
be email for our required attribute for sign up and everything else we're just going to hit create and over here we can see all of this we can ignore everything that's happening here we're just going to select Amazon Cognito go to our user pool see that we have this new user pool over here it is not the name we named it so what we are going to do is rename it for the re uh user pool name I'm going to call this re Cognito user pool like so and save change now over here I'm going
to click app client and you can see that we have our Cognito app client and important thing is going to be this client ID which is what we're going to use and over here you can see everything that is based here and you can do whatever you want we're going to leave all of this pretty much the same and what we want to do is go to sign up and in our sign up we are going to have if you take a look this is the signup attributes that we have username which comes by default
email which is what we added as well as password and confirm password but we actually have a role over here and this role is not provided normally by Cognito that's where we can add a custom attribute and these custom attributes will be attached to Cognito and it's some value that we can store into Cognito and we can use it so we are storing R in this custom attributes and we're not going to change anything else and we're going to hit save changes and you'll see custom colon roll note that I wrote roll the custom colon
is prefixed and that's pretty much it for every setup that we need to do for Cognito I just want to let you know the users are going to pop up here when a user signs in we're going to be able to see the user over here you can manually create a user if you wanted to and then there's also groups this is if you want to do more like role permissions attribute permissions things that involve roles and having access to different AWS Services you can use it with groups and there's a lot more other settings
you can use we're not going to get into all of this we're just going to keep this quite simple the main thing we are going to need is this userpool ID and the app client ID I showed earlier so I'm going to hit copy over here for the userpool ID and we're going to go back to our code we're going to go into the client directory and I'm going to create a new file over here I'm going to call this EnV in this EnV I'm going to create a new environment variable called next public AWS
Cognito user poolcore ID and we are going to paste the value of your user P don't use you can use mine if you want but I'm going to be deleting this after I know some of you guys just copy and paste what I have and you just try to log in there but you should probably create your own Cognito or else you're going to have a rough time I'm most likely going to delete the Cognito and then what else we're going to do is we're going to just copy this and this is going to be
userpool client uncore ID and and we're going to go back to our AWS we're going to hit app client and we are going to click on app client and hit the copy to clipboard for our client ID and paste it over here and just while we're at it we want to route we're just going to say next public API base URL this is for calling our backend and our backend is going to be at HTTP localhost 3000 and that is our end point for our backend so just as a reminder if you go to index.ts
process.env Port is where our backend server is running and that is based on this port over here and this is what is going to be used when we call our backend and we haven't really talked about it but in our API we are actually using that public base URL to make calls to our backend and we'll cover that very soon all right so the next thing is we are going to be using amplify UI for our front-end authentication now amplify terminology is a little bit confusing because AWS has a service called amplify where you can
ho host apps like nextjs onto its platform in AWS service similar to what you would see on Bell but there is is also AWS amplifi where you use it kind of like a toolkit the one we're talking about right now we'll use amplify the service later but the one we're talking about is the SDK or the code version and we're going to be using that for authentication so in the link in the description I have a link to all of this and what we're going to look at is over here in react we're going to
find the authentic component this allows authentication to be pretty easy with react it does get tricky when you're doing multi-step forms but for our use case this is pretty simple once you know how to do it it is tricky to figure it out but that's what I'm going to show you today so as you can see this is the authenticator component that we are going to be using we have a sign in and create account we're also going to customize this to make it match our theme and our application as we have seen before and
what we're going to do is we're just going to write code with the authenticator component and I will tell you how to do this in our application so just as a reminder this part we are creating for the authenticator is going to involve this section where we already created this Cognito now we need to create the UI for this and later on there's another part where we do have to send the Cog user information that'll be later but for now we're going to deal with this part so we can connect the client with the sign
in sign up to Cognito so that is the part we are going to create so over here we're going to go back to our application and and we're actually going to create a new folder we're going to call this o we're just grouping this for now and inside here I'm going to create a new file I'm going to call this o provider. TSS now I'm going to go back to our authenticator code over here and you see this boiler plate we're just going to use this and we're just going to copy and we are going
to paste it if you don't want to copy and paste you can just pause it and just write it out over here but we are going to make some changes here and we're going to make some pretty big changes so for starters as you can see there are a few things that we do need to install and that's going to be aws-amplify and aws-amplify slui react so we're going to open up our terminal and I'm just going to close the server out and we're going to navigate to our client directory via CD do Dot and
CD client so we go in here and I'm going to run npmi aws-amplify and I'm going to do aws-amplify slui - react and again we're going to get this pure dependency issue because of the new react 19 so yeah I don't know why they have done stuff to make this a bit of a headache but we're going to do Legacy dasp do DS all right so everything here is pretty good we're not going to create a new separate file for aw- exports we're actually just going to fill this AWS exports out ourselves and this is
going to be an object and we want to configure O Colon Cognito colon and this is where we are using userpool ID colon like this process. env. nextt and we're just going to go to ourv we're going to copy this entire thing for the user pool ID so we're going to paste it over here so that should be good and we're going to put an exclamation mark That's because we are forcing it with no defaults and then we are going to do user pool client ID colon like this we're going to do process.env once again
go back to our en EnV file copy the client ID paste it over here with an exclamation and we can save it and if you're curious where I got this information you can tell over here in this link in the description I have authentication Amazon Cognito you're going to have all of this information you can put all of this login with is optional but this is everything you need and we have basically these two set up I'm just going to paste that link over here just in case you guys want to sometimes it's nice to
just have this link just in case all right and then from here we're going to change a few things inside our return we're going to do div I'm going to set this to be a class name and we're just going to give it a height of full so this is so the authenticator is not part of the background so we're just going to make the entire height full and we're going to encase it with the authenticator inside our authenticator we're not going to have any of this we are going to do this slightly differently and
we're just going to pass in children like this and I'm going to change this to be const o so I want to change the name of it a little bit we're going to pass in children colon children colon react. react node like so we're going to do an arrow function just to be consistent with how we have set this up in other applications or other pages and I'm going to do export default o like this so we have our authenticator and this is good for the basic and now from here this o is not connected
to anything but that's exactly why we have our provider's component if you remember this has our Redux store now we can just add the authenticator as well so inside here I'm going to put this on new lines I'm going to do authenticator and we are going to grab it from AWS amplify and we actually need to do this provider like so and we are going to make sure we encase the children within it and also we also need to encase the oth component that we created and I'll tell you why exactly this is It's supposed
to be like this this authenticator provider needs to surround the the authentication because we're it uses react context and when we want to use the authenticator aspect over here in our oth provider for example I want to grab user from use authenticator in AWS amplify Ur uh UI react we are grabbing basically the context and we are doing context. user this this use authenticator needs a parent component of authenticator provider for us to use that's why we have this over here normally you don't have to do that but if you want to use the user
value up here then you need to do so now let's go to our client I don't think we'll be able to see anything maybe we do but we're going to run npm runev we're going to go to our application and we can see if we go to over here here which is slash signin you can see that we already can see that we already have all of this and if we go to sign up we also have this for now so right now the sign in sign up doesn't fully work properly but the reason why
it's styled already a little bit different from what we see in the authenticator if you look at this this is how the default looks like but that's because I've already added in the global C s if you remember we copied and pasted this into our application I already have a bunch of Amplified UIC CSS styling over here and if you wanted to um if you wanted to style amplify you can use these as a guide but basically all I did was if you go over here you can select whichever one you want and then you
can see the class that that you want it to modify and you add that class and then you add whatever style you want it's a little bit tedious but as you can see with for example let's take a look button primary you just have to first have data- amplify authenticator and then you add the class and that allows you to Target that specific class so everything is me styling it myself but right now we're not fully there there's some things we need to change with our component and that's what we're going to be doing so
this authenticator component it is a little bit weird I'm not exactly sure what the thought process is on why they made this component like this where they have two properties of components and form Fields I'm not exactly sure what the purpose of having those separately it does make confusing when you're dealing with complicated scarios so we're going to have both of these and these allow you to modify the components or modify the form Fields And if you want to customize it further you can use components as well so let's start with form fields in this
case so right below the configure we're going to do const form fields and I'm going to do an object and where I want to do is if you go back back to the amplify UI react documentation if you go customization you're going to be able to see that they have a lot of things that you can customize it's all about trial and error sometimes but form fields we can set what is supposed to be shown in form fields for signin and then also sign up this these are all the type of properties you can add
you can set up your own as well but for us we're just going to do sign in Colin with object we're going to do user Name colon with placeholder is going to be enter your email and then label should be email with capital and is required to be colon true and I'm going to just take this copy it paste it over here and this one is going to be password so our signin includes username and password and we're just going to change this to password pretty simple as well as the label should be password as
well all right I'm going to copy this entire thing for sign in but we're going to do something similar for sign up so I'm going to change this to sign up over here and the user name we can also set the order by setting this so this will determine the order of the form field that we are using so then the placeholder is going to be choose a user name for sign up and the label is going to be username as well and is also required same thing over here for password we're going to do
order to actually this is going to be email first we're going to do the email and then enter your email address with label email and make sure you have this comma after order I'm going to copy this because we're going to have two two more fields or maybe three for this one we're going to have password we're going to take the order 4 three and here is going to be create a password and the label should be password as well and I'm going to paste it one more time this is going to be confirm uncore
password this order has to be four and this is going to be confirm your password and the label needs to be confirm password and that should be it for our form Fields so this is kind of determining the logic and they do have prebuilt components or pre-built components for form fields and it's already going to be set up but we are still missing the custom role manager and tenant for this one and there's a lot of other things we want to add as well that's where the components is going to be using so I'm going
to go over here I'm going to say const components and we going to get an object and components consist of a few already pre-built things and the way we do this is with for example header that's going to be the thing at the top and over here we are going to import View from 8s amplify these are kind of just divs but it is the amplify way of doing it so you want to make sure you do it to amplify way I'm going to close that view and make sure we pass in heading as well
and we are going to do level three just realize this is kind of like material UI it's a little bit they just have some preconfigured components that you can use uh I wish they would just not have their own you can just create your own via Tailwind but better to use what they're recommending for their usage but over here we're going to have rent like this and I'm going to say span with a class name and this is where I'm actually going to use Tailwind secondary 500 with font Das light and then hover colon exclamation
text primary 300 to make sure we are targeting that correctly and we're going to do if so in this case we're actually defining our component customizing it versus just the form Fields where we are identifying the inputs so it's a little bit different it is a little confusing they should have just made the components and then you would just identify it somehow I I don't know I feel like there might have been a better way to do this because it just does kind of make it confusing to set this up so here I'm going to
set the text muted to foreground with the margin top of two give it a span with class name of font dbol and we are going to do welcome with an exclamation and say please sign in to continue and we are going to save it and let's actually take a look and there you go we have our heading so this is pretty nice so this heading pops up on top of the other components that's what this represents and then there's also sign in so we can customize our signin part which is right here like this middle
section so we're going to do sign in with friend invocation actually my mistake it's not a invocation it should be a colon and inside here we're going to add a footer as well and what we're going to do is do const to sign up use authenticator and this is for the little text that we're going to have below where it says don't have an account sign up here which will add a link this will allow us to take us to the signup component page and over here we are going to return I'm just going to
copy this entire thing because it will make it easier so I have to write it I'm going to write view as you can see it's right underneath we just have a copy of it but we want to change this so we're going to say text- Center margin top of four and I'm going to remove this heading we are just going to do d p class name text is equal to text muted D foreground close this out and we're just going to say don't and if you want to do a a posy sign you can just
do and AOS semicolon T have an account question mark we're going to put like this so we have a space so that below we can do a button and we are going to set onclick and this is where the two sign up is useful and we are also going to add a class name of text primary hover colon underline oops underline so that when we hover over it it's going to be underlined with a background of transparent border of none and padding of zero we're going to close that up and we are going to say
sign up here actually this should be lower case to make it look a little better and we're just going to remove this P tag save that and it looks good I think I did make a mistake so grab this closing P tag it should be around the button as well and there you go and make sure you have a space using something like that so that they are separated a little bit so don't have an account sign up here perfect that looks pretty good to me and there you go that's our sign in now we're
going to do the same thing thing except it's going to be for sign up so below sign in I'm going to do sign up colon curly braces with form Fields this time and inside here we're going to add something called validation errors to use the validation errors if we need to pass it in and we're going to do use authenticator once again and we are going to return we're going to put empty tags and this sign up form Fields so for now let's let's comment this out I just want to show you if I go
click sign up here we are seeing this right now we have the username email password that came from all of this so we didn't even create any components this already created it for us but we do need to add the user role at the bottom of this so there is a trick to do this and that is if we use authenticator there is something we can pass in which is sign up. form Fields so this passes in all the form fields that we already have so we should keep everything that we already have but we
want to add something below it so if I want to do that hello is at the bottom of that right here so instead of that that we want to add radio group field coming from AWS amplify and we also want to make sure we close that out so inside here we're going to set the legend to be Ro so that's the basically the label name and the name is going to be if you remember custom colon roll so remember we created in our signup [Music] this custom attribute of rle but it got prefixed with custom
colon so that represents custom attributes so you want to add that and we are going to set the error message that's going to be validation errors question mark dot brackets with custom colon roll like this so this is how you can make sure you have validation check for this C system field I'm going to copy this once again and this is going to be has error and that's going to depend on the validation errors so there's going to be a double exclamation and that will determine when the error should pop up and we are also
going to set this to be is required so to make sure that people select one of the options and the options we can do with radio element so that's going to be a value of tenant close that and we're going to put tenant like so I'm going to copy and paste this this should be manager as well as the option should be Capital manager and when we save it as you can see we have a role of tenant and manager perfect and the last thing is we need to be able to go to the signin
page there should be some text at the bottom where where we can link it so we're going to go up over here grab this footer go down and under form Fields make sure it's in the right location we want to add this footer but this time this should be to sign in instead we're going to keep everything pretty much the same except this is going to be already have an account like so and I'm going to say to sign in everything could remain the same except sign up here should be sign in so once I
save it you can see it says already have an account you can hit sign in goes back to the previous sign in sign up Pages Perfect all right from here let's give it a test so I'm going to go to username I'm going to erase just some dummy email that will be the username and the email will be the same thing with at gmail.com so make sure you're used your own email for all of this the username does not have to be the same thing as email you can just do whatever you want and then
the password I'm just going to do one two three Apple be's with an exclamation just use whatever password you want so this is just going to be a fake user account make sure you can do with a confirm password and if you change this it gives you validation errors which is perfect so all of this is already set up for for you by AWS that's why it's very nice to have something like this to make sure everything is good and even if I hit try to create again account you get validation errors so that is
very good so in our case I'm going to just hit tenant so I'm going to hit create account and now you can see that this is pretty cool we emailed you your code is on the way to make sure you're login you're going to enter the code that you get from your email so I'm going to go to my email I'm not going to show it here I'm going to copy and paste the confirmation code and hit confirm and as you can see even though it goes to the sign up page says this page canot
be found which we will fix a little bit later but the way you can check if it worked we're just going to go back to the landing page and I'm going to open up our Dev tools via alt command I or whatever or you can just find it in your application and what you want to do is you can check if it actually has signed you in if it signed you in you can go over here and you can see all of these values over here and if you are signed in you should be able
to see all of these Cognito identity service providers in the local storage of your application so all of these Cognito IDs these are all your authentication and credentials that you have received from Cognito and this is how you use Cognito to make sure you use authentication so this in our diagram is all the credentials sent to the client right here we haven't set up the nav bar and anything else to make sure that indicate that you are signed in we'll get to that but for now relishing the fact that you have have sign up so
if I wanted to sign out you can actually just do clear that'll clear everything on your Local Host I had too many things anyways so I'm going to refresh you're going to see in our local storage we're not signed in so let's actually try and sign in actually before we do that we can see we we'll go to users and you can see that we have our user already created and everything else is there we have a Cognito ID by the way this sub represents our COG NE ID I'll cover that soon we also have
a custom role value of tenant so this is going to identify the role that the user has so every all the information is over here which is very cool and we can delete the user if we want to so we would hit delete and it would give you options if you wanted to but we're going to keep that let's actually go over here to sign in and I'm just going to do put our email I'm going to do one to three Apple bees exclamation and we are going to sign in and let's see if that
worked out and there you go we have our Cognito ID and everything over here we don't have all the extra stuff because I had other things on Local Host 3,000 but this is everything we need so you're going to see these cryptic messages which is ID tokens and jot tokens so it gives you a lot of information and we're going to actually decrypt it so we can see what is actually happening in that and remember this is Enterprise level so they have a lot of security a lot of things going on a lot of complicated
things but which is very good for your Enterprise level application but before we get to do that uh we're going to do a little bit of routing handling before we leave this code particular file so we are going to do we're going to use router from use router from next we're going to grab that and we're also going to grab the path name to identify what page we are on so we're going to do use path name like so and we're going to do if is O page as a variable so that is when we
do path name. match whether it's slash or forward slash with you know the top tick like that forward slashback slash and then we're going to do sign in with a hor ver vertical line they sign up with the dollar sign and then forward slash semicolon so this is a regx we're just checking if it is off page meaning if it either is sign in or sign up that's all it's doing and we're also going to check if it is dashboard page which is something we'll set up a little bit later and we're going to do
path name. starts with Slash manager and we're going to do or if path name dot starts withth is equal to slash tenant so that is going to determine if we are on the dashboard Pages which is the pages we haven't created so everything else is non dashboard and for now it seems like I did not import to use pad name so we're going to save that and we are getting this error make sure you're using use client and also the problem is with use rather this is not the one you want to be using we
want to pass the use rou we want to grab it from the next navigation not exactly sure why they have two of those forms but we have this and that should work it should be both from next SL navigation so there is a few things is that when the user is signed in we want to redirect authenticated users away from the off pages so remember when we signed up it we got a 404 that's because we are signed in we want to redirect the user away so the way we do this is we're going to
use use effect and we are going to do our Arrow function and we're just going to do something simple if the user exists so that is exactly why we are using us authenticator we want to check if the user exists and if they are on the o page so on the signin sign up page we are going to do router. push for slash like this and we want to do a brackets like so and we want to pass in user is off page and router like that so this will make sure we redirect authenticated users
from o pages so I'm just going to add that comment if you ever forget why we have that and then also we need one more other thing is to allow access to public Pages without authentication so for these non- dashboard Pages we need to be able to allow the user to see without requiring authentication so right now we are signed in but let's say for example with all of what we added if I cleared this I cleared the sign in stuff we can't go to those landing pages it's blocked so the way we need to
do this is we're going to add a condition over here so we're going to say if it is not o page and it is not is dashboard page so we're checking if it's not one of the O pages and if it's not one of the dashboard Pages we just want to do return and we are going to shortcircuit everything so we have zero authentication for those pages so we're going to save that and as you can see with our landing page this has free access same with it's going to be the same thing for search
page which is something we'll create as well so those pages do not require authentication only for the pages where it is a dashboard and this basically handles that situation and the last thing is when we hit sign in sign up it's going to start with the incorrect uh sign in or sign up Pages it doesn't work properly so we need to do an initial State and we're going to do path name. includes we're going to say sign up like so and we are going to do sign up so that if the URL is/ signup it
actually goes to the sign up component otherwise we want to start with sign in component let's just make sure the authentication works properly so now if I go over here if I hit sign in we come to this page and if I go over here sign up should take us to this page right here that's exactly what this line does all right so the next thing we want to do is if we go back to our diagram we have taken care of this part this part and all of these sections but we also need to
handle this right here where we grab the Cognito ID send it to our authorizer and to our database so we first need to save the user information into our database and if it does exist we grab the user info so we can send it back to the client and that is exactly what we're going to be doing and there's a couple things we need to do so I'm going to close a lot of this and I want you to go to the the API file now we haven't written any kind of endpoints yet but this
file is for Redux toolkit and this particular one is called api. TS this is for Global store if we want to save any state in our Global store while this one is to make any API calls and the way this works is Redux toolkit is very nice the only thing is the terminology is kind of annoying because they use a a lot of fancy terms to explain things that are pretty basic when you have a base query that's the base URL that you're going to be using for this particular API in our case it is
Local Host 3001 which is where our server is located so this is where we are going to use and then the endpoints are going to be the specific endpoints at that base URL of which we are calling so to start off we're going to create an endpoint called get off user colon and then we're going to do build. query and we're going to be passing in a typescript and we're going to use the interface user which is a type that I identified earlier and I'll go over what that will look like and in here we're
going to have an object so whenever you use Redux toolkit query you're going to have a build. query this is just something you typically normally do and then the typing this is what we are going to receive back this is what we're going to be sending to the back end these are both typescript typings and then from here we're going to call something called a query FN so this is just a query function and we are going to use something with async now it comes with a number of params the first one we're just going
to skip when we put an under uh underscore like this that means we're not going to to use that prams this is a very common thing in software development anytime you're not going to use these attributes you're going to just put a underscore because we don't need any of these params however we need this last one so this is going to be Fetch with base query like so and then we're going to have an arrow function so it looks very complicated but this is just typically how you set up an endpoint with a query function
inside here and inside here we're going to have a try catch block like so and so when you sign in in off provider when you hit that sign in button you're going to be able to access the user information and to access the user information we can use a function called Fetch o session which comes from a amplify o so we do something like this and we'll be able to grab information about the user via this fun which is basically the session information now I'll cover this in detail what each one represents but let's go
and in our session we have something called the ID token so we do session. tokens question mark question mark we initialize it with an empty object just in case so this is so we don't deal with typescript errors and if it doesn't initialize we're just going to create an empty object that's fine so we need this ID token but there's also other information we need the Cognito ID which is what we can get from get current user which is also from adways amplify off so we need both these information so session and user and this
is all information like I showed you before in our local storage those are information we're getting from Cognito when we signed in and then finally we can grab the user role which is something we can get from the ID token payload and that will be retrieved by selecting that attribute and we're going to set this as string because it doesn't know where it's coming from so this is the user R we can grab from the ID token and also the user information gets from the get current user and now from here once we have the
user information we are going to try and fetch the endpoint from or the information from our own backend if it exists so we can create some variable called us uh endpoint is equal to user Ro and we can say it is equal to manager and in this case if the user is a manager we can say managers SL user. userid or slash tenants slash user user. user ID something like that so that would be the endpoint now we haven't created these end points just yet which we will do shortly but in this case we would
do something like let user details response is equal to await and we can make API calls with our base query with Fetch with BQ endpoint like so so this will call the endpoint depending on if they are a manager or if they are a tenant we're going to try to see if we could get information back if the user ID already exists otherwise we're going to do something else we're not going to do it right now but if user doesn't exist we're going to create a new user so that follows the pattern that we have
over here so we're going to check we're going to grab the credentials that we got from Cognito to the user and if it already if the user already exists we're going to send that Cognito ID to our backend see if that backend already has that user information and that will send it back to the client if it exist if that user doesn't exist then we'll be creating the user first and then retrieving that user information back to the client and that will work just like that and once we have done that in Redux to toolkit
you can just do return and we're going to place this in the data object and we are going to put all the Cognito information that we have into a property called Cognito info we're going to do that and the user info is going to be the user details response data so all the information that we get back from our own database will go into the user information whereas Cognito is spread into the Cognito info property and we are going to set this as tenant or manager depending on which role they are and we are also
going to set the user role which will either be tenant or manager now these are not created but it is already created in our Prisma types and like I said before with the Prisma types we have this tenant created based on the data model so it is type safe automatically when we use something like like that so this is why it is really cool to do something like this so now we have tenant and that should be properly typed and for now we're just going to give this an any just to make things simple we're
just going to do return and we are going to say error error. message if it already exists or if the message exists otherwise we're going to say could not fetch user user data like so so that's pretty much it on the front end side of things right here we also need to create one more thing and I know this is quite complicated but this is how you make your authentication very secure and up to Enterprise level standards so right here is all the fetching of the user information but we need to make sure that when
we make an API call we send the right credentials to the back end for any back end you don't technically in real applications you don't want your public or your API end points to be public and exposed to random people who might dos your website for example for your API generally you want just your front end to be able to interact with your backend apis now it really depends on the scenario but in this case where the API we want is private we need to send credentials to the back end anytime any AP CL not
just this one but any API calls requires authorization and the way we do this is we can modify this base query which is very nice because in R toolkit it provides you with all the tools to make this super easy and what you do in base query and this is very standard practice when you are authorizing any API calls is putting it into Heathers your authorization token into headers so we do prepare headers call an async headers like so with an arrow function and what we want to do is again grab session via this line
once again and we're also going to grab the ID token as well and if the ID token exists we want to set the headers with an extra attribute called authorization comma with Bearer space ID token this is very common practice this is very a lot of times when you're making an API call you have a header we add an authorization header with a bare ID token this allows the user to authenticate any API calls that they make in any API call so if I create another API call here I'll get some data from back end
this will automatically attach the header to that API call so that the user is already authorized so that makes it very nice and simple all right so I know everything I'm showing you seems very complicated but I'm telling you this is what you would deal with when you're dealing with real Enterprise level authentication if you just use other managed Services it can kind of be you'll run into different issues you'll run into more annoying issues later down the run but if you're dealing with an Enterprise level application having something like this set up is very
nice because you have a lot of custom control and companies have a lot of very custom needs when it comes to security most people don't understand when you're at an Enterprise level company they have very strict and high security type requirements and something like this is knowing this in detail is very very helpful all right so now we did the front end for all of this we don't have these end points and we're going to create that soon we're going to create that now so the next part is going to be creating these endpoints and
that's going to also play into creating you know user settings and things like that because we are creating user information on our back end so now let's go down to source and into our server once again actually let's so we want to create two different routes for manager and tenants so that we can grab the user information if it already exists but we also need the middleware that checks if the user is authorized so now you can use Cognito authorizers to automatically confirm that it's that Cognito authentication is legitimate but in our case we're going
to create it we'll talk about this later when we deal with API Gateway I know I know I said we using Cognito authorizers we're not technically using it but we're doing something similar ourselves so over here and I'll explain why we are doing it ourselves as opposed to using it there's a annoying reason why we're doing it anyways we are going to create a folder and we're going to call this middleware inside this middleware I'm going to create a new file I'm going to call this o middleware dots and we're going to write some code
so we're going to do interface decoded token extends JWT payload so a lot of this is going to involve some encoding and decoding and we are going to do SUB colon string which is going to represent Cognito ID and the custom colon r with a question mark we're going to say this to be string so we're essentially grabbing the typescript uh value we get from JWT payload and we're going to add custom roll on top of it and we also want to do one typescript interesting thing with declare Global for the namespace express which is
already existent this is like a typescript thing we're going to add interface request and we're going to add a user colon ID colon string with rule colant string I'm not going to go over this but this is more of a typescript thing we're adding onto the interface request that already exists for typescript so that we can handle the authentication better so with all that we can do export const o middleware and this is the function that we are going to use to check if the user is valid or not and we are going to do
allowed roles colon string with an array and we are going to return Rec colon request with res . response comma next is colon next function from Express and we're going to do colon void like so so basically a lot of typescript stuff we're not going to go too deep into that so from here we're going to do cons token we are going to grab the request headers do authorization so that is the authorization I talked about we're going to split it with an empty string like so to grab the authorization value all right and then
we're getting this error that's because we're not actually using the right request this request is coming from native JavaScript it needs to come from Express as well so we're going to do that so that will cause no issues and this should be allowed roles not and then from here we're going to say if token does not exist we're going to say res. status 401 . Json and we're going to give a message of unauthorized like so and we're going to return now if you take a look where this token is coming from is what we've
created over here with the headers we are head setting the headers for authorization and we're doing be space ID token and this regx is basically splitting it and we're grabbing the authorization token that comes from this section right here and then with that token if it exists we're going to do a try catch block here we're going to do decoded so we're going to decode the token using JWT do decode like this with the token and we are going to use as decoded token now this JWT comes from Json web token so we're going to
do J WT comma it's a way to decode the token because it's uh encrypted we want to decode it using that and I will show you what these actually represent but for now let's do decoded custom colon roll and with an empty string so this is the rule as well so we're going to decode the token and we can actually grab the ru from the decoded JWT token and then from here we're going to grab the rec. user we're going to do ID decoded. sub to grab us the Cognito ID then we're going to grab
the r with user roll like so so this is the request user that we are creating and we're adding it to our you know API calls and we're going to see if const has access and we're going to say allowed roles do includes user user roll. two lowercase and now I'll explain what this will be doing very shortly and if has access does not exist then we are just going to copy this over here pass it over here we're going to say access denied denied like so and from here we're going to have a catch
block we're going to say error console. error failed to decode token colon comma space with error we're going to do res. status 400. Json we're going to say message Callin invalid token and we are going to return after and because we are doing this with a middleware we want this to go to next if none of these errors were triggered so essentially what we're doing I'm just going to summarize this entire thing is that we're going to check if there's a token the token's not there we're going to give them unauthorized but the token is
there we're going to decode that token grab the user R put it into the request user and also if the user has access so if the allowed roles includes so that dependent on what argument we pass in here incl includes that specific role whether it's tenant or manager then we're going to say access denied and if none of these errors trigger we're going to be able to go to next that's exactly how middle Wares work they are placed on routes which we will create so if I wanted to I can add this same middleware say
off middleware pass it in here and let's say I would do like manager I think it's more like this you would place it in there and that will mean that the user needs to be a manager to access this route so that's how this middleware will work otherwise if you're not if you don't have access it's going to trigger all those errors and the API call this API call will not be allowed that's how we make our authentication all right from here now we can actually create different routes so first we're going to do do
something called app.use and we are going to create the tenants route first and we are going to pass in the off middleware like I mentioned and this is going to be an array with tenant and we're going to do tenant routes so that means all the routes which we will be creating inside this particular variable all of those routes will require us to be authorized with our custom role of tenant this is exactly what we just created with this a middleware and the decoded token will allow us just that and just to give you an
idea of what the token actually looks like so let's actually take a look so right now I am not signed in so I'm going to do just that so once we're signed in you can see that we we get multiple things there's a couple of things that we have we have access token ID token refresh token signin details clock drift not exactly sure what that is for but everything else is information refresh token is when the token you know expires this is going to be used when the token expires you don't have to worry about
doing anything with that that's automatically handled with Cognito but ID token is the main thing we're going to be looking at and if you take a look it's just a list a long list of strings which means it is encrypted and the way you can actually see what's happening with this token is you can go to website called jw. and here you can actually just pass in your encoded token and you can see once it gets decoded it actually looks like this this actually has all the information about the user this has a lot of
information including the user name that I used email verified also check the sub which is the Cognito ID that we're going to be saving and even the custom role with tenant so this has a lot of information that we're basically decoding and grabbing over here we essentially grab the sub from the decoded JWT token and also the custom roll with user roll so isn't that refreshing to understand what is actually happening this is encrypted just so people don't normally see it and understand what's happening but it's a way to encrypt and it is used for
security all right with that in mind now that you understand the authentication part let's actually create the user information that we'll need to create for our tenant route so over here where it says route Imports one of them is going to be import tenant routes we have not created and we are going to grab it from SL routes SL tenant routes and typically when you set up an Express backend you generally have a folder called routes where we will place all the routes relevant to a specific feature and in this case it's going to be
tenant routes. TS so inside here is going to be pretty simple we're going to do import Express from Express like so actually this should be a string and then from here we're going to do const router is equal to express. router this allows us to have this router in a separate file and we're just going to do export default router and we are going to create our first route which is router. getet and because we passed in cognito ID on the front end that is exactly what's going to be over here managers or actually tenants
in our case SL user. userid this user ID represents the Cognito ID and that is exactly what we're passing in and by the way it has the terminology of being called sub as well by cognito I'm not exactly sure why they have such different terminology all the time they should just make it consistent so it's not confusing so we're going to have a get tenant route we're also going to have another route and we are going to call this route. poost and this is going to be for creating the tenant so we're going to create
both of these routes so we can create the tenant if it doesn't exist and get the tenant if it does exist and we are also going to create an import for these even though it hasn't existed yet we are going to say get tenant and then create tenant and we're going to import it from something called slash controllers slash tenant controllers like so we're going to create both of those let's actually rewrite this so that the typescript or like the typing or the linting basically knows that it exists and then we're going to create a
new folder we're going to call this controllers and and we are of course going to call this tenant controllers as well so inside here we're going to do a number of things we're going to first import request comma response from Express and we're also going to import and this is for us to access a um access our Prisma client we're going to import Prisma client so that we can initialize and call our backend database so we're going to do const Prisma is equal to new Prisma client we're going to invoke that and the first thing
we're going to do is create export cons get tenant so this is pretty simple but this is going to be the basic structure of how we create our backend endpoints so we have expert cons get tenant it needs to be asynchronous and it's going to return a promise with a void so that will be the result of what we invoke and we are going to do a a TR catch block and we are going to grab Cognito ID from the rec. pram so from tenant routes this Cognito ID we can grab it via this value
inside Express and once we have that we can create tenant and make an API request to our database using Prisma client that we created doing Prisma do tenant which is already type safe and we want to do find unique so we want to find the user with a specific Cognito ID so we're going to do where Cognito ID exists and we're going to include as part of it this is kind of like an SQL query meaning we are also grabbing their favorites as well so we are essentially doing some join um join queries inside Prisma
but this is kind of how they do it it's a little abstracted which is both good and bad and if the tenant exists we are going to do res. Json tenant otherwise we do res. status 44. Json message is going to be tenant not found and in our backend we are going to do catch error colon any and we're going to do res. status 500. Json we're going to do message error retrieving tenant colon error. message like this so this will allow us to grab the Cognito ID or allowed to grab the tenant with our
Cognito ID if it exists so if you go to our Prisma schema and I go to tenant over here you can see that we have a Cognito ID we have a regular ID which is incremented from starting from zero to one or I guess one but Cognito ID is what we are fetching the tenant based on and they will all have Cognito ID inside the information and you can check also if this is a little confusing for you you can also check the mock data that Cognito ID exists for each of these and you will
use those to make requests or to find the tenant that you are looking for now by the way there is also favorites and there's something called connect this is a way to connect to a different section or like to connect different properties as well so this is basically grabbing different properties and determining which one the user is favored it which is something we'll get to eventually um but for now we have this get tenant we also need to be able to create the tenant as well if it doesn't exist so we do that by doing
export const create tenant and you know what let's actually just copy this entire thing paste it over here and we can start changing things from here so we're going to create tenant save that and we have this and instead of grabbing the Cognito ID from the rec. prams when you create a tenant we are actually not putting it in the prams we are going to be sending it since this is a post call we're sending it in the body itself so the Cognito ID name email and phone number are all going to come from the
body instead of the prms so that's how you grab that information and what we want to do here is Prisma do tenant do create like this and we want to do data colon like so and we're going to pass in actually all of this let's just copy this we're passing all of this information so we can create a new tenant and we're just going to do res. status 2011 pass the Json of the tenant if it's successfully created if it didn't create we are going to say error creating tenant like so and there you go
we have our endpoints for get tenant and create tenant all created so that we we can do what we mentioned earlier so let's actually fix this just rewrite this and grab it from our linter to make sure it's not screaming at us and might as well while we'll do that before we check if it working I'm just going to go and do the same thing for managers because it's pretty identical of what you have so if I go over here slash managers we going to change both of these to manager routes as well as the
off middleware and then we're going to go back up here copy this change this to manager routes and of course we have the tenant routes I'm just going to copy and paste this entire thing and I'm just going to rename this manager routes there you go so we have manag routes and tenant routes over there so in our manager routes we just need to change this to get manager same with crate tenant this should be manager as well actually I'm just going to select all of them with command D multiple times I'm going to change
all of this to get and create manager like this and this one oh forgot this one as well so that should be manager controllers and once again I can go to tenant controllers copy and paste this inside controllers I'm going to rename this one to manager controllers and over here most of these with tenant I'm going to do command D this this is a little bit of a trick so if you click this capitalization I'm going to do command D for any we are selecting all the capitals of the tenant we are going to change
this to manager like so and then we're also going to do the same thing for lowercase manager and select all of them by hitting command D multiple times change this to manager as well so most of this should be good except include favorites manager does not have properties they favorite it they're the landlord so they don't they're not they're not people who have to deal with favoring managers they own people via management and same thing with create manager all of this looks pretty good and we don't need to change any of this so we should
be pretty good once again we want to make sure there's no errors with that make sure this is manager routes I did make a mistake earlier for our route UT and everything looks good we have our tenants we have our manager routes and we have our API so this is going to fetch our backend when we do so however we still haven't created this part where if the user doesn't exist we need to make an API call as well so essentially if user details response. error and we're going to check if there is an error
and if user details response. error. status is equal to 404 meaning the user was not found from the get request so essentially we go to let's say this is a tenant we're going to check if the tenant exists so we're going to try and call this route get tenant but the the tenant is not found we want to trigger this section of the logic on our front end so then we are going to do user details response and we are going to actually grab it from a new function and we are going to create a
new function called create new user in database and we're just going to abstract it because it does I don't want this function to get too messy we're going to do Fetch with base query and actually when I added this we already have this function in our utils I've already created it um I'll just show you we we aren't going to write it but it's basically very similar to what we have done but if you do if you look at this create new user in database we are going to grab the particular endpoint that we want
to use once again we're going to do Fetch with base query once again except this time this is going to be a post call so we are setting the URL which is the create endpoint via this SL managers or SL tenants we're going to give it a method a post and we are going to give the body information of everything we want to send to the back end and we're just going to do a little bit check if we get an error that means we failed to create the user record otherwise we de create or
we return the create user response which is the user new user information will be sent or returned to our user details response and that will be used in our user info so the final thing we actually need to do is that right now we identified the endpoint for get off user but we're actually not invoking this function in any of our components so to invoke any of these end points we're going to have to actually invoke this function inside another component so the first thing we do need to do is we're going to do use
get o user query so anytime you have one of these functions get o user all you have to do this is just part of the process is that you just write use get o user which is the name of your endpoint and then you tack on query or if it's um a mutation called then you put mutation which I'll cover a little bit later so for now we're going to go to our layout page which is in non dashboard and in here we are actually going to invoke that function and the way we do this
is we just put we can destructure the data and call this o user like so and we grab use get o user query from our API call and it's it's just as simple as that to invoke this function so if I open this up in our inspect by the way in our local storage I already cleared this information so we are not going to have any information and because we have this API call that's going to make this into a client component so we're just going to use client like so we're going to save this
and we are going to go back to our console and see that o user is undefined because we are not signed in in which is what we expect so to test this out let's actually create a new account we're going to hit sign up over here which will take us to this page and once we have our information I'm just going to hit create account and I'm going to use I'm going to get my confirmation code paste it over here and hit confirm now before we go back to our landing page you want to create
a new terminal going to open this up a little bit and we want to go into our server directory and we want to make sure our back end is of course running so I'm going to run npm run Dev and now we can go to our slash landing page all right and now what's going to happen is that you are going to get an error response saying that the user is not found for that particular message which is exactly what we expect because this is a 404 error so when the error status error right here
is going to be 404 we should technically be creating a new user now if you take a look at the network tab we we can see that the first one is an error manager not found which is what we would expect and as you can see there is a second API call let me open this up this is post and then you get 2011 created which is exactly what you would expect so let me open this up in tenant controller when we created this we had create tenant and a 21 means that the user and
the tenant has been actually created and actually is my mistake I think this is a manager yeah this is this should be a manager that got created which is perfect so now if I go to console if we look over here we have the Cognito info so this is all the user information we're getting from Cognito at least the ones that we need and then also the user info yeah Al also the user info over here which is the information that we are saving to the back end now we're not going to handle adding a
phone number um I didn't want to add another field cuz it complicates things but we're just going to keep it simple have this with no phone number with email name and phone number and I think this is incorrect Majestic that should be Majestic gmail.com or something so yeah it there was a mistake if you want to really fix this this is actually where you can get the email with the session if you go over here in session you can go to ID token payload and email is where you want to grab it instead of where
I got it so if you want to fix this we can just do let's say email probably we can do email colon session actually instead we can just pass in ID token over here to create new user in database so we can do ID token let's just put any and over here we're going to do instead of user signin details login ID we want to do ID token. payload do email and we do want to make sure if they don't exist we have that value so that is how you grab the email for now it's
not a big deal um I didn't change this in the code asset that I gave you but this is how you would fix it um and any future user that gets created is going to have that ID token as well so I'm going to erase all these console logs and we can now see with all of this in our landing page that we should have all the O user and we can use the user information as we please we have the user role as well the Cognito ID the email which is incorrect here but we
also have the regular ID the name and also Cognito information as well we can also add session over here but we probably don't need it but if you wanted to you can add all that information here too if you wanted to and with that we have all the information for our authentication pretty much set up I know that was a lot there's a few other things that we need to do for like you know user information we can grab this user information put it over here to put extra details and whether you know a few
routing things as well as navbar stuff that involves user information but we're going to handle that just next but I do want to review everything we did this is quite a bit I know there was a lot to this and I know it seems a very complicated but at the end of the day it's not too bad you just have to understand the process of what you need each time you do authentication and a lot of what I did involves Enterprise level standards so if you go over here we started with creating this oth provider
so let's actually move all of this over here so you going get distracted so we have this uh 8s amplify authentication so that is the main part of the UI that we saw when it cames to sign in and sign up so we can see all the user information over there now obviously let me go to application I'm just going to clear this so that we can actually go to sign up page so this is all the UI authenticator stuff that we have and made sure that we connected it via the providers this is how
we authenticate it we did some routing to make sure that there is no routing issues and then we also set up the Cognito information in AWS as well so that was this part where we did process AWS config that and that is what we have over here with app client and the Cognito user pool that we created pretty simple stuff and then on the back end we have middleware because we want to make sure the user is authenticated via the headers so any API calls made to this back end is making sure that the user
is correctly identified by Cognito and we have this prepare headers that shows us the authorization and the bearer token and then we also added this get off user this is how we are authenticating the user so if the user information does not exist then we want to make sure or if the user sorry if the user signs in has the Cognito ID we want we are going to make an API request to the backend to see if that user exists or not in our database so not in the Cognito user pool but in our database
and if it doesn't exist in our database we are going to create a new user and we did this with our backend over here with their tenant routes we have create tenant if the user doesn't exist and we grab the tenant if the user does exist same thing same exact thing with manager routes and the off middleware like I mentioned is where we decode the JWT token to make sure that the user is who they say they are and that will make sure our API works correctly and then from here next up we're going to
deal with the Navar and our sidebar using the new authentication and we are going to do some routing as well all right so with authentication mostly out of the way we're going to finish up with the last few pieces such as the nav bar so we have when you are signed in we we need to show the user's name as well as this button which goes to the dashboard settings and sign out so these are the last few things we want to do with our nav bar so we're going to close all of these things
and we are going to open up go to our client and we are going to go to navbar over here now there's a couple things to note that if you are on non dashboard page this text appears but if I go to the dashboard that text is gone so we're just going to make some conditional modifications to our Navar as well and we are going to also have some routing things determining that so over here in our navbar I'm going to do const data colon off user and we are going to grab use get o
user query from our API which is all set up perfectly fine and we are going to do use router and we are going to grab that from next navigation and then from here we're also going to grab the path name we are going to use use path name from next navigation and we are going to create a variable and say is dashboard page is equal to path name. includes and if it's slash managers or path name that includes slash tenants like so and then finally we are going to create a function which will handle sign
out for the user and we are going to have an async function and all this is going to do is await sign out and window.location.href is equal to/ FL now this sign out should come from AWS amplify off so with AWS amplify you're given this function and it does exactly what it says so it's perfectly convenient and this one we are not using router simply because router does not refresh the page correctly so we want to just actually use the window.location HF so that makes sure we don't have any problems so below our link over
here we are going to add a condition if is dashboard page and if the user exists we are going to add a certain condition and that condition is going to be a button for the user so we are not going to deal with this right now but the search property is what we have we don't have the text that we saw before but we also yeah on the non dashboard page we do have that text so we're going to create the button in this condition over here so we are going to grab the button from
from Shad ins Side Bar and my intellisense is not popping it up actually it's already there so it doesn't really matter the button is over here and inside here I'm going to give it a variant of secondary with a class name of mdml 4 background primary 50 text primary 700 hover background secondary 500 hover text primary 50 and on click what we are going to do is this one is going to involve router. push so the push will be dependent on the button op user. user roll to lower case is equal to manager we are
going to take them to a new property which is something I'll talk about later and you'll probably see what is going to do new property so it's just going to take you to two different links depending on whether you are a manager or if you are a tenant it's just going to take you to different pages under those conditions nothing too fancy and then over here we are going to say if the user is manager we are going to to give a little bit of a different icon in this case we are going to grab
plus from Lo side react do class name H h-4 with -4 we're going to close that and also do a span of class name we're going to do hidden and if it's larger than medium screens we're going to do block with margin left of two and we are going to say add new property over here we are going to add another little icon we are going to do search from lose side react we're going to do class name is H4 W4 like so and do another span as well we're going to do class name is
equal to Hidden MD colon block margin left to close that we are going to do search properties and we aren't going to be able to see it on our application so we're going to continue and over here right now we see this we want to make sure this only happens for the text when it is non dashboard page and we do this by adding that condition like so so again it won't change anything what we currently have but it will change when we are doing dashboards and over here we do want to make sure the
user is signed in and we're going to show two different things depending on whether the user is signed in so all of what we have currently with this link that is when the user is not signed in so we are going to have something like this shown inside here this is where we are going to have to write some code and we also need to add an empty fragment around on this double link so we can have that and then this should be off user instead and over here this is where we are going to
write the code to make the little uh the tag where the user is signed in so over here I'm going to write D div we're going to do class name is going to be relative hidden MD colon block and inside here we're going to do message circle from lose side react give the class name of width 6 H6 cursor Das pointer text primary 200 hover colon text primary 400 close this out and we're going to have a span over here do a class name with absolute top -0 wr-0 with two H2 background secondary 700 rounded
Das full and we are going to close our span we're going to save that and we're also going to have another one we're going to add a div if you take a look let's actually go to landing and yeah let's actually sign in first and if you take a look it we have this notification with a little red dot showing that we have some kind of notification um the only problem is we have this little white dot it seems like I guess it was correct for the constant to have 44 I think this is the
correct Navar height yeah it seems like that's the correct value I don't know not exactly sure what's happening with the height thing it should be consistent across but for some reason it's not very consistent so we're setting it to 44 as the height that we have all right inside here actually we're just going to copy this entire thing except we're going to change a few things we're going to call this a bell now none of these will actually do any kind of functionality but we're just doing there to make everything look nice and we are
going to keep everything else the same so as you can see those two pop up with notification icons and then from here we are we're going to use Shad CN using drop- down menu and that should come from our own UI component not radic so we want to use that and we want to use drop menu trigger as well and we're going to do class name is equal to flex items D Center gap of two Focus colon outline none close this out pass in avatar from our UI Shack CN components we're going to do Avatar
image as well we're going to do source is equal to Au user. userinfo do image like that for Avatar image and finally we're going to do Avatar fallback just in case do class name is equal to BG primary 600 inside here we are going to take the off user user rooll with a question mark do0 do2 upper case we're just going to take the first letter as the Avatar image fall back and finally we're going to have a P tag this is going to be the name that's next to the little icon so text primary
200 with hidden and block status with au user. userinfo mark. name and then below this we're going to have drop- down menu content we're going to grab it from R Shad CN Library not from radic so class name is going to be is equal to BG white text primary 700 close that out and we're going to have drop down menu item from our own I'm going to close that first right go to dashboard but we are going to add a few things we're going to do class name is equal to cursor D pointer with hover
colon exclamation background primary 700 with hover exclamation text primary 100 font Dash bold and on click we are going to have an arrow function and this is going to navigate to the correct page and again this is going to be dependent on whether the user is a manager or a tenant so I'm going to go up copy this value and go down paste that over here and we are going to do slash managers slash properties if they are a manager otherwise we are going to take them to the tenants favorite pages and we also want
to set scroll to be false like so so we don't get some weird warning okay so that looks pretty good we're just going to take this copy it down over here and we are going to add drop down menu separator from Shad CN and we are going to give this a class name of BG primary 200 self closing and over here this is going to be different this time this going to take template string I'm going to close this out like this and do slash settings like this make sure you have this plural so this
will go to whether it's managers or tenants SL settings so that looks pretty good and then finally we're going to copy this one more time go to this bottom part everything will be the same but this time we are going to use handle sign out that we created earlier so the user can sign themselves out and if I save it you can see we have this uh I did forget to change this to be settings but if we do that we have go to dashboard settings and sign out and also you see the font bold
we're just going to remove that so those two are not B so it does seem like it's kind of messed up if you see that so let's go back up and see what the problem is and yeah so the problem is this ptag should be outside the Avatar right there and then there you go we'll have something like this and there you go and when you click on it you can go to dashboard settings or sign out the user all right and then there's one more thing that I want to add before we go to
the next thing which is the sidebar is just the one little thing that will make our lives easier in the future and I'll explain this as we go if it is not or if it is the dashboard we're going to add a div over here with class name we're going to do MD hidden so it's hidden on larger screens and we are going to add something called the sidebar trigger from our Shaden sidebar so this will basically allow us to control the sidebar allow us to close it when we are on the dashboard page and
I'll expl expl this once we do the sidebar so we're just going to save it like that all right so the next thing we're going to be creating is going to be the dashboard pages so that is going to involve tenants and if the user is manager they're going to be taken to managers and then a set of properties over there so there's going to be a number of links and you can see over here on this diagram that we have a number of pages like favorites residences uh residence and applications so so this is
actually there's a few more um navigation items which I got I removed because of the scope I got rid of billing history and payment methods but settings is there application and Residences and the individual residence page and then also properties property application and the settings page for manager exist so there's essentially four pages for each and we are going to create this sidebar which is critical for for the navigation now it's going to be able to shrink and open and also when we go to a smaller size screen there's going to be a sidebar trigger
that will open up this sidebar and we can close it as well made but now there is fortunately Shad CN so all the work I did there is now a sidebar component that I can just use it makes it very nice it is annoying to style a few things there's a few things I don't fully understand when they're used using it but they do have a lot of examples and you can see that they have a decent amount of documentation for this and we're going to be using this to create our sidebar so let's get
to it so what we are going to first do is create a little separate folder we're going to call this dashboard and this is where we are going to have separate layouts for this we're going to do layout. TSX and in side here I'm going to use rafc and I'm going to call this dashboard layout all right so inside here the first thing we want is that we are going to be using our nav bar as well so Navar we're going to pass that in from our components and we put it into the components directory
because we are reusing that and so we can reuse that for our specific use case and that's why we made all those changes specifically for dashboard and then over here we are also going to do style and we are going to do a padding top colon of Navar height like we did before so everything placed underneath the Navar is below the Navar height and then below this there's going to be a main section we are going to use class name of flex and under here this is where we are going to use sidebar now this
is not going to be any of these this I know this is from Shaden we're going to create a separate component that's going to be using this Shaden sidebar so we need to do a couple things so we're not going to import anything for this sidebar and below this we're just going to have another div we're going to do class name of flex grow transition make sure you spell that correctly transition in all with the duration of 300 so that when you open and close the sidebar it smoothly animates and over here we're going to
have a children and finally I do need to add some class names over here with Min H screen so it takes up the entire height with a width of full background of primary 100 and close that out and the children needs to exist so we need to pass that in we're going to do children colon and then children colon react. react node so we have that but we also need one other thing for our sidebar sidebar needs to be wrapped around something called sidebar provider and that comes from our act components UI sidebar so this
is necessary for Shad CN sidebar so that this can have the context the react context state that is provided by this so now we are going to create a new file and we are just going to call this let's actually call this app sidebar so it's slightly different from the naming of the shad cn1 and I'm going to do rafc again and we're going to have appside bar like this now in here for the type we're going to do user type because we need to have different sidebars depending on who or what role they are
so if they are manager or tenant and as you can see I have this interface app sidebar props that's one of the typescript types I set up a while back so we're going to be using that and to start off we're going to use path name name from next navigation so we're going to grab that and then we're also going to do toggle sidebar and open so this is um this is react State we can grab from our UI sidebar so toggle sidebar allows is a function that opens and closes the sidebar so anything like
when you saw over here you can see that this this has a function called toggle sidebar and open is a Boolean that determines whether it's open or not so we're going to be using those and then from here we are going to create nav links so this is all the nav links we are going to create for our entire application for our side bar and there's a number of links that we are handling this is a pretty big app there is several multiple pages for all of this so we're going to start with an icon
of building from blose side react and we're going to say labels colon properties for the first one and this is for managers so we are going to have a link of Slash managers SL properties so that will be our first link I'm just going to put an empty array so we have uh linting doing its job right now so over here I'm going to copy and paste this next one let's actually close this so we have more space and over here the next one is going to be file text so I've already pre-selected all the
loose side react icons I just want to show you just in case if you ever need to search up icons you can go over here let's say you want some people you can use something like this in Search and then you would take this you can figure out what icons to import based on the icon you choose so you can use this you should be able to find that all right back to our code here is going to be applications and it's going to be manager SL applications and I'm going to copy this again let's
actually copy this two more times we're going to change this to settings with the label of settings and managers going to include settings I did forget to import from lde react actually there's only three pages I I totally forgot I only have three pages for manager or I do have four pages but only three nav links for manager and then from here I'm just going to copy this entire thing paste it over here and this is for this is the links for um tenants and we're going to start with with favorites and favorites are always
going to have a heart icon for lucide react and we're going to change all of these managers below to tenants and I'm going to change this to favorites and file text can remain the same because that's applications um settings can remain the same but there's actually one more link for um tenants which is going to be home icon with residences and tenants SL residences so these are all the nav links that we are going to be using and then underneath here we have our div we're going to change this to the sidebar now we can
actually use our shadan sidebar and there's a lot of things we need to integrate in here so let's start off by adding a number of properties over here so I'm going to do collapsible we're going to set this to be an icon so that means it close when you close it let's look at this when you close it over here when you close it over here it turns into icons you can make it so it goes it's all completely hidden but if you wanted to do something like this you would set the collaps to be
equal to Icon and then over here we're going to do fixed with left of zero background of white and Shadow of large and we also want to set the style cuz sometimes when you do this with class it doesn't really work especially with some hardcoded values like Navar height we're going to pass this in like we normally do and then also height as well the height needs to be the entire height minus the Navar height and the reason why we want it we want the nav bar to um or the sorry not nav bar the
sidebar to take the entire height and the way you take the entire height is you subtract the height from the Navar as well so if you take a look and we open this up the entire height needs to be this entire section right here all the way down minus the nav bar which takes up the entire width so we do that by doing calc 100 uh viewport height minus navbar height pixels like that so that will give us the perfect amount of height so that the sidebar takes the full entire height and then the sidebar
header is going to be the first thing we are going to set and that is going to include this section right here this part right here these two guys not these links but these two right here and the close button those are the sidebar headers so inside here we are going to do sidebar menu we're going to bring that in close this out we're going to add sidebar menu item as well and then inside here we're going to have a div close this space add class name and we haven't used something like this but we're
going to just use CN which is class names it makes it a little neither to write not fully necessary you can use template strings but sometimes it is a little bit nicer we're going to say Min height of 56 pixel for this one this one's just hardcoded so I know exactly the pixel size we're going to have a width of full items Center padding top of three margin bottom of three we're going to do comma open so that means if the sidebar is open we are going to set some classes we're going to do justify
between px6 colon justify Center if it's not open so different padding sizes if it's open or closed so this part was a little tricky maybe I'm not doing the CSS styling right but I did have some rough times trying to modify it to get the perfect sizing so it it looks okay over here it's still not perfect to me like it's almost it's centered but it's not fully centered and when I do this when I open it it's a little UNS smooth so I don't know maybe you can figure that out I was having some
trouble with styling that so over here we're going to have an H1 with class name text extra large font D bold text of gray 800 we're going to close that out and we are going to do if user type is equal to manager we are going to set the text to be manager view otherwise we are going to set renter View and then over here we're going to have a button and this one is going to represent the x button so it'll minimize so we're going to have a class name we're going to set hover
with background gray 100 padding of two rounded MD and onclick we are going to set toggle sidebar so that is the thing that allows us to collapse the sidebar icons and we are going to make sure we import X from loose side react with class name is going to be H6 with six text of gray 600 and we are going to close that and then below this we're going to have another condition if it's already closed we are just going to copy this button over here but instead change this to be a menu from loose
side react and keep everything the same so as of right now we can't really check if this looks okay so we can go to layout let's actually create this act component slidebar and what we are going to do is we're going to create two folders we're going to create managers and we are going to create tenants and inside tenants I'm going to create a new um new [Music] file actually sorry a new folder called favorites so this is the correct padding and inside here I'm going to do page. TSX and I'm just going to do
RFC uh favorites like so and we're going to save this and let's see right now go to dashboard does not oh actually it does and we do seem to get this issue when we're trying to use it so in our Navar we do need to do use client because we are using interaction I'm going to save it as you can see it looks pretty good but uh things are cut off the height is not working correctly so let's actually fix that all right so I did some modifications for some reason I changed the N or
height again to 50 I don't know sometimes maybe I'm not doing this correct 50 looks pretty good to me favorites it's almost there maybe it's cuz the width I don't fully know maybe like if it like do 52 then it's like the perfect height yeah play around with it see if you get something similar I'm not exactly sure I'm a little confused on that so as for the sidebar there's a reason why it's not working because I am a silly person I imported from at component sidebar when in reality I should have imported sidebar from
at SL components slapp sidebar so you want to make sure you're importing correctly and in this case case we need to pass in a user type the user type should be um basically from the use uh what was it the the O user use get o user query and we want to make sure we pass in O user. user roll to lower case so that should be the user and if we use something like this we want to make sure we do use client because that only works in client components and we want to make
sure it exists so the way we do this we're going to do something like this if o user question mark user roll because there's a null check with typing we want to return null so something like this and as you can see we now have renter view over here which is exactly what we want that's a little bit annoying figuring out some of the issues but we have what we are supposed to see so we have the header and if we click this it goes down perfectly it's very smooth and responsive so let's keep going
and let's keep continuing finishing up our app sidebar so under sidebar header we are going to bring in sidebar content like so so that is going to represent the rest and then from here I'm going to do sidebar menu we're going to bring that that seems like it's already imported so we need we don't need to import that and inside here this is where we can actually use nav links so we can do nav links. map and for every link we can go and create an react elements so is active is if the path name
is equal to link. hre so if it is the current path name we can set it to is active so we can do return and we are going to grab sidebar menu item we're going to set the key is equal to link. hru so we don't get react performance issues we're going to do sidebar menu button and make sure we import this one close this out and inside here we're going to give it some props we're going to say as child class name and we're going to use use the CN Class Property once again we're
going to do Flex items D Center px7 p-7 comma is active and we are going to give it different colors depending on whether it's active or not and so we do text Gray 600 with hover colon BG gray 100 like this and then finally we also have another condition if it's open we're going to do text blue of 600 and then over here we're going to do margin left of five pixel to give it centering when it's collapsed all right that looks good and then from here we are going to import next link because everything
the navigation items are going to require a link to another page so we're going to do href is equal to link link. href with a class name of with full scroll is going to equal to false as well and then over here I'm going to do div with class name of flex with items - Center gap of three and then inside this we can do something with link. icon as an element we're going to make sure that's a self-closing tag we're going to do class name we're going to pass in H5 with five and inside
here if it is active we are going to do text blue 600 colon text Gray 600 as well and below this we are going to do span we're going to have a class name of font D medium is active and actually we can just copy this over here paste it over here and close this out as well link. label will be what we have and if we do that we should see favorites application residence and settings and you can see everything is highlighted perfectly fine if I click on any one of these links it should
take me to the page even though it does not exist so right now those pages do not exist but we do have the link and it's going to the correct page and as you can see we had the search properties that we created before this is exactly what I was talking about this should take us to the the/ search page and there you go some of the styling for the app sidebar can be kind of annoying to deal with but it does make life pretty easy making you be able to do something like this so
when you go and it's small enough we can also have this by the way there are some issues with dialogue content these are console errors you don't really need to fix it if I had more time I would fix it but in this case it's not a huge deal you know and before we go to the settings Pages um there's one last thing I want to do which is just quick few routing things so when you are on the dashboard page so on the front end you want to make sure the user gets routed to
the correct pages when they click on different buttons and make sure that managers cannot go to tenants and tenants cannot go to managers so we are going to add that logic inside here inside the dashboard layout now next does have like this router thing that they do have but you can't really do it with this because of our authentication a lot of times I'm not exactly sure how they expect you to do it with authentication maybe there is um but with Cognito I find that you have to do it over here all right so in
our layout page we're going to add router is equal to use router make sure we import it from next navigation not next SL router we're going to also do c path name with use path name as well we're going to do that and we're also going to make sure if it is loading we are going to add that otherwise we can keep it like this and we're going to import State as well and we're going to set true to be the default and so what we are going to do is a use use effect to
make this routing happen and this will happen if the user is already authenticated we're going to grab the user Ro from the information granted it's provided to lower case like so and we are going to say if user Ro is equal to manager and path name. starts with Slash tenants or let's actually just copy this so we don't have to rewrite this nonsense there's actually an extra PRS or if the user is tenant and starts with managers so basically if they are if they're a manager and the path name starts with tenants we are going
to make sure they get routed to the correct Pages otherwise they're they'll be stuck on the manner Pages versus the user uh the tenants pages so I'm going to say user Ro is equal to manager otherwise we do slash managers SL properties and slash tenants slash favorites like so otherwise we do scroll colon false so making sure that the user if they land on the wrong set of pages we bring them to the correct page and we also want some kind of loading condition so we're going to do set is loading to be false and
also we want to make sure we have the correct dependency so Au user anytime that changes or the router or the path name we make sure we retrigger that and if Au loading or is loading we are going to return loading for now we're just going to keep it like that now this off loading is something we can grab from Redux toolkit query which will make things easy so we're going to do is loading and off looing like this and that's pretty good we're just going to go over here we're actually just going to copy
this entire thing from here everything from there to the if condition and we're going to go and fix the non- dashboard pages so over here I am just going to paste that entire guy all over here in non dashboard and we're going to make some changes of course we want to make sure we import correctly from next navigation same with this same with use State same with use effect and from here we're going to make a few changes so if the user Ro is a manager and path name starts with search or user R is
equal to also manager we want the path name is equal to slash like this make sure we close that then in this case we are just going to do one thing we are going to push them into SL managers SL properties like so everything else can remain the same make sure we grab is loading is going to be off loading like this and we can just remove this return null section over here and make sure we do have a comma like this the whole purpose of this is that if they are a manager the manager
can't search for properties unless they sign out we just don't want them to do it otherwise we're going to have to deal with extra conditions and this just makes it convenient so with that we have finished everything when it comes to authentication navigation routing everything in regards to that so pat yourself on the back because this is real level authentication that most people are not going to give you they're going to have you use some kind of um easy authentication but they are not Enterprise level all right so the next thing we're going to create
is going to be the settings page so for the settings page we have just a simple input this will be pretty easy we're going to have name email phone number as you can see this is disabled but if I hit edit you able to change any of these values and you can hit save change so that should update that user information in our database and remember this is information that's going to be changed in our database but not Cognito we're not going to deal with that because that's will be more complicated so we are just
going to stick with this as our settings and we are also Al going to change the back end to to include this save change endpoint so we are going to open up we're going to go to we're going to close the client for now and go to source and inside routes we're going to go to tenant routes first and inside here I'm going to do router dop put like this slash colon Cognito ID and this time is going to be update tenant which is what we'll create and note that for update put is the correct
um method for this you can use post for my understanding but put is the correct one we're going to do update tenant and we'll be creating that in our tenant controllers so we're going to open that up and create our endpoint and this should be pretty simple so I'm just going to grab create tenant copy this and paste it and over here let me move this so we have more space I'm going to change this to update tenant the Cognito ID is going to come from the rec prams so unlike the create it is not
going to come from the body it just come from w. prams I'm going to remove the name or Cognito ID and keep the body the same and in this case instead of create this will be an update and over here instead we're going to have a where we're going to pass in cognito ID like this with a comma and then for the data we're going to remove the Cognito ID and on res. Json we're just going to do this for our tenant and let's actually call this I'm going to hit hold alt erase this and
then do update tenant like that so we have two cursors I I just used two cursors and changed it and instead of error creating tenant I'm going to say er error updating tenant and that should feasibly finish this up and we're going to do the same thing for manager routes it should be pretty much identical so we are going to go over here I'm just going to copy the router. put that we had from tenant routes paste it over here and call this update manager I'm going to put this update manager above here and I'm
going to go to manager controllers and I'm going to go to actually before I do that go to tenant controllers copy the update tenant go down and we are going to paste that and we are going to grab all the ones with tenant and make sure this Capital matching is there so we're going to say update manager and over here this is tenant this should be a manager as well and as well as this and that should be pretty good so pretty straightforward now that we have everything set up so I'm going to close up
our server and now we can grab and create API endpoints to make this API call and to do this with everything set up it is pretty straightforward from here so I'm going to get the same line as get off user which is closed over here and I'm going to write update tenant settings colon and this is how we can make this is going to be a mutation call query is for any get request mutation is for any put or post or delete so anything that changes the data so mutation and we are going to pass
in tenant which already exists and it seems like this should be something like this which is already being imported and then comma Cognito ID colon string and we are also going to do partial tenant in these angled brackets so essentially what this is doing let me add that what this is doing is we are going to receive tenant from the back end and what we're sending to the backend is Cognito ID as well as a partial tenant what that means is we don't have to give out everything for the tenant to update we just have
to give you the updated things updated settings to the back end and then from here I'm going to put an invocation and inside here I'm going to do do query colon Cognito ID dot dot dot updated tenant like this with an arrow function like so with URL colon tenants SL Cognito ID so if you remember with this URL this is going to be the end point that we are specifically targeting so we're it basically uses the base query which is um this next public API base URL in this case it is Local Host 31 and
then it also adds tenants SL Cognito ID for the endpoint that we are going to Target and then from here we do need to specify a method which is going to be put and we are going to add the body updated tenant and then from here we actually need something called inv validates tags so I haven't you want to make sure it's just a property this is this is something I haven't talked about but essentially inside Redux toolkit you have tag types so this is essentially uh state that you are saving and you are naming
it a certain thing and in our case we have two tags that we want to create which is managers and tenants so these are the two state that we are saving it into our back end and so in this case the tenants if we already have a fetched list of tenants in our Redux State on the front end that means we want to update anytime we fetch new or when we make this query we want to fetch new data just to make sure that our front-end data is aligned with the backend data and that is
exactly what this is doing it is built in and it kind of does this all for you which is very good and the way we do this is we're going to set this type to be tenants but we also need to make sure the ID is the correct ID and update the correct tenant as well so if you have a list of tenants we need to make sure we update the specific tenant that we are updating and then from here we can keep it like this for now this is an API call and all we
have to do from here is do use update tenant settings mutation this time it's going to be a mutation call so this is an API call that will call the API query that we just made and then from here I'm going to grab this update tenant settings I'm going to change this to update manager settings like this I did command D I selected all of those and also this tenant should be changed as well so manager and and this one should be managers as well I believe this is plural yeah make sure you have the
correct plural versus singular that's very important otherwise you get a lot of bugs and we are going to do the same over here to use update manager settings mutation and we're going to save it and we have three API calls just like that all right so from here this settings page is going to be completely identical to the manager settings page so what I'm going to do is go over into our components and we're going to create a new file and we're going to call this settings form because we're going to be using it in
two different spot so over here I'm going to do rafc make sure settings form is all there and we're going to get starting on our form now in our form we're going to have couple properties over here it's going to include the initial data the onsubmit function and the user type and this is going to have settings form props so that is interface of typings that will be relevant for our setting and first off we're going to create some state so edit mode versus set edit mode so that will represent us being able to edit
just like that and I want to make sure we do use State we're going to set this to be false and I'm going to also do const form and we are going to be using use form from react hook form react hook form is a pretty nice form Library it is the most popular one that people use so we're going to be using that and also I'm going to get settings form data which is coming from library schema now this is something I've already set up we're not going to deal with this because it's already
set up don't worry about this too much but it's basically just validation shows you name is required we're just using Zod to validate our inputs I don't want to make you guys suffer for me to write because a lot of that is kind of very tedious but it does and it takes a lot of time so I I feel like it doesn't give you guys a lot of value from here I'm going to do Zod resolver which is going to be imported we're going to import Zod resolver like this from hook form resolvers and then
you also want to do Zod like that and what we do is we pass in settings schema from library schema and we also do default values callon initial data and then from here we are going to create a function do toggle edit mode and we are just going to set this with an arrow function we're just going to do set edit mode to be edit mode like this so we're just reversing it but if edit mode is already on when we turn it off we want to do a form. reset which is a built-in function
and we are going to reset the data with the initial data and then finally we are going to do handle submit so this is will be the function make sure you spell that correctly we are going to pass in for our data settings form data as well do an arrow function and we're going to do a wait on submit so that's going to be passed down from the parent component which is dependent on tenant tenant page or the manager page and we are going to do set edit mode set this to be false all right
and then from here we're going to do class name and I'm going to just set this to be padding top 8 padding bottom five px-8 and in side here I'm going to create a header I'm going to call this div class name of margin bot 5 like so and inside here I'm going to do an H1 tag with a class name of text Excel font D semibold I'm going to close this up I'll write the title in a short bit I'm going to have a paragraph tag with class name with text small text gray 500
margin top of one and I'm going to close that and inside the title right here for the H1 it's going to be in curly braces user type. character at zero to upper case and then we are also going to do user type. slice of one and then we're going to a space we're actually going to do this a template string so like that and this actually needs to be in curly braces like this and put settings like that so we're able to use the user type rule we're capitalizing it basically and putting settings over here
and the subtitle is just going to be manage your account preference is and personal information all right pretty straightforward that will be the Heather for the settings form and below this this is where the real form will be so we're going to do div class name and it's going to be a background of white with rounded extra large and right now we're not doing anything visible it's not going to be shown so don't worry about that this is just the final product we're just trying to imitate so from the form we actually want to grab
it from U y/ form not the react hook form because we're going to be using Shaden form which is abstracted on top of react hook form as you can see there's so much abstraction when you have too much abstractions on top of each other it can be very bad when it comes to like if you have a lot of when you need to customize it a lot then it starts become a problem but in this case it is not going to be a problem so over here in our form when you have when you have
this form you have to still specify a form on top of it like that and we are going to do onsubmit and we are going to pass in the form. handlesubmit which comes from react hook form and we are going to do in parenthesis handle submit so we are passing our function that we created over here into form. handlesubmit I know it's a little wild because of all the abstractions it becomes a little confusing but it makes life simple all right so with this form there is something that I did forget to add it should
be in your asset drive that I didn't tell you before when we had the asset download remember we had the asset download I actually added something behind the scenes which is a form field component this is a allaround form field component it has a lot of things a lot of validation a lot of different type of inputs and I made you know there's some bugs here and there but it is useful because it'll abstract a lot of the Annoying code for writing the form in a real case scenario I would show you how to do
all this but forms and inputs are usually a big pain so we're not going to deal with that so instead we can just use the abstracted version and I'll just tell you what it's exactly doing so we are going to do custom form field and we are going to do name name like this with a label of name capitalized we going to say disabled is equal to the opposite of edit mode and we're going to do just like that so this is very very straightforward if you take a look custom form field it's going to
have a name of name with label you know capitalized and disabled so that means this is how it's going to be saved in react hook form this is the label and we're going to make sure it gets disabled as we need and by default there is a type property that I have but by default the type is just a normal text input and then from here I'm going to just take this copy and paste it but this time we're going to change a few few things we're going to do email with a label of email
and in this case we can actually do type of email it makes it very convenient here that I have the custom form field to do this otherwise it's a lot of pain you have to do validation for email you have to do all of these annoying things sometimes but that's the life of a front an engineer so over here we have the name of phone number label is going to be phone number like so but we don't we are going to have just a normal type of text so we can just leave this be below
this I'm going to have another div I'm going to call this class name is pt-4 flex justify Das between and inside here we're going to have a button and we are going to grab the UI button and we're going to say type is equal to button for onclick we are going to set toggle edit mode with a class name of BG secondary 500 text to White and a hover of BG secondary 600 I'm going to close this out and inside here this will be depending on if it's an edit mode or not we're going to
change this to be cancel or edit and also So based on the edit mode we are also going to have a save changes button so we're just going to grab this button over here we're going to remove most of this we need type submit so this is actually submitting the form and we are going to change this to be BG primary 700 we can leave the text to be white and we can just say background primary 800 and instead of this edit mode we are going to say save changes and save it so this will
be the settings form that we use for both the tenant settings and the manager settings so with that let's actually close all of this because too many things open is problem and then over here in our app this is where we're actually creating the real page so inside tenants we need a new folder we're going to call this settings and over here we're also going to have a new file for page. ttsx and in here I'm going to do rafc call this tenant page or tenant settings all right so here we also want to check
or grab the user information so we have o user once again and we are going to grab use get o user use Query as well so make sure we are able to grab the user information and by the way I know I'm calling it here but I'm also calling it in the layout over here so you might think oh that's going to be a duplicate API call actually no it's if the information's already there and it doesn't need to be updated this is going to use the cached information if it already exists it's just like
react query Redux toolkit query is the same thing except it saves it in global store which is very nice and very convenient that you can just access this anywhere all right so if you remember so we have o user now if I console log this let's actually we need to do use client because again we are making an API call we're going to save this and we are going to go to our application and I want you to realize I'm already at the settings page so you would you can go from favorites you can click
on settings and when you have settings you can load it up and see that our object includes a lot of information and this is information we are getting from the back end so what we want to do is create initial data and we are going to set this to be name to be o user Dot userinfo dotame and then we also want email to be Au user question mark user info. email as well and phone number should be exactly the same just going to copy this over here we're going to say phone number as you
can see so that represents this object we have all the information in our Au user so we can use that we also need if is loading we're just going to grab this to be is loading as well just in case the user is not loaded we are just going to return uh loading States so that is going to be done via this for now and that should be good so this is going to be the initial data we do pass into our form and another thing is we're going to require the function of use update
tenant settings mutation this will be part of the handle submit and the way we use a mutation call is going to be a square bracket instead of a curly bracket and we we can just call this whatever we want we can say update tenant it doesn't really matter update tenant is a function this makes the most sense but we want to grab use update tenant settings mutation and that is going to be invoked just like that so this is a function call that will you can pass it anywhere and if you invoke it it will
update our tenant settings make an API call there let me close this I'm going to open this up so we have more space so the way we do this is we're going to create a function called handle submit and we are going to do an async with data colon type type of initial data because that's going to be the type that we want to send to the back end and we are going to do await update tenant like so we are going to set Cognito ID colon o user question mark. Cognito info. user ID so
we need to make sure we send that as well as the rest of the data that we are sending in our form so the handle submit if you remember gets passed into settings form so the handle submit is over here we are passing an on submit function which is going to be this function right here and we are passing the data which we receive from the form which is going to be all the new inputs for our settings page and then from here we can just erase this and instead we're going to put uh paren
and we're going to do settings form from at components setting form close that but we do need to pass this in and we are going to pass in an initial data and then also on submit with handle submit and the user type of tenant and if I save that we should be able to see that we have the tenant settings we do have no phone number we can edit it but this should technically work we can change and modify if I hit cancel it's going to go back to what we originally had so this is
all our information so let's just do 111 222 333 save changes and let's see what we get back let's make sure that we performed a network call I'm just going to refresh the page and if the information is updated like this that means it was successful and let's actually check our terminal you can also check your terminal if it worked um when we made a put request we had a 200 which means it was successful so yeah that basically worked and now we want to do the same exact thing for our manager settings page and
it's very possible that in this application we could have just you know the settings page could just like we could have just put manager and tenants as the same table in the database we could have feasibly done that because they're so similar all we had to do is add a property on the table of type manager versus tenant but I decided maybe in the future you would change things so having it separate sometimes helps so it really depends on your use case so we're going to create a new folder we're going to call this settings
and in here I'm going to create a new file called page. TSX and all I'm going to do is grab everything in our tenants file copy that and paste it over here and just make some adjust ments here so over here instead of update tenant we are going to change this to update manager so I selected every single tenant in the page I'm going to change this to manager singular and everything else could be exactly the same except for this part with user type this should be manager and that should be good to go and
that's pretty much it we're not going to I'm not going to show you because I'd have to sign out sign in but but it should be pretty much identical to the tenants you can verify yourself all right so we have the setting page and the authentication before we go any further this is something I keep forgetting but it's better late than ever I want to upload this repo even though it's not finished onto GitHub and the reason why I'm doing this is because if I have like a section of completed repo you guys can do
like checkpoints to see if what you have in your code is correct sometimes you want these checkpoints and you can see where I make these checkpoints and this will be the first one for this so I did miss you know some sections but at the very least if you did not get and if something's not working right you can check out this particular git commit if you know how to use uh git well enough you can figure out how to check out this particular Branch to check if all the stuff you have been doing works
properly so to create our repo I'm going to close all of these both these servers and what I'm going to do is go over here in our client directory now nextjs already creates a git but we don't want that so I'm going to do reveal INF finder and the whole purpose of this right here is depending on your system for Mac this is hidden so you want to show your hidden files and I'm going to delete both the dogit and dogit ignore so I'm going to move to trash you can also use rm-rf to remove
that particular folder it will be that will be for Mac but for Windows it might be different we're just going to remove that because we want to do a git command on the top level right here so going back to over here I'm going to create a new file I'm going to call this git ignore first so we can ignore a number of things and I'm just going to copy and paste this you guys can pause the screen and add all of these git ignores so this is so you guys can or it this will
ignore certain things in your code so that you don't push it up you definitely don't want to push up node modules the disc files the emvs definitely and maybe some like extraneous things like this those are important not to push up and from here I'm going to go out of client into our Parent Directory mine's just called run but in here I'm going to do get a nit and initialize our git repository and then from here I'm going to do get add dot so that adds everything for our file and then do get commit I'm
going to call this first commit and I'm just going to do o completed something like that so you guys can figure out that this is when we finish the O it's a very noteworthy section so that's why I want to make sure we have this set and then from here I'm going to create a new repository feel free to update your own repository and push it up and follow what I do and I'm going to just fill this out real quick so this is what I have I'm just going to call it real estate-pr and
I'm I'm going to hit create uh create repository and inside here it gives you a number of command lines but the only one I'm interested in is this particular line get remote at origin so I'm going to go back to my code after my commit I'm going to add that hit enter and I'm going to do get push origin master and if all goes well you can go back to this page on GitHub refresh the page and you'll be able to see client server like this and you'll see your commit happen and you'll have everything
you need to pull it down so I'm going to have this git setup it's going to be updated later in this video but if you ever need to double check at this checkpoint so you don't have the final application you can check it over here you can do so as it is available all right so from here the next thing we're going to be handling is going to be the properties page and the back end now the properties page is going to be one of the more complex pages of the entire application aside from authentication
but we should be able to get through it there's a lot of moving pieces and I'm going to tell you why it's so complicated especially when you're doing sort search and filtering which is a very tricky concept when you're doing front end and even back end as well but before I go into the nitty-gritty of doing this specifically for properties I want to talk about the concept between doing it on the client side versus server side you can filter sort search and do pagination all on the front end basically on the client or you can
do it on the server now there's a couple trade-offs with this now most people probably when they start doing front end they're going to be doing all the filtering searching sorting on the client I'm going to tell you why it's not always the case where you can use this but essentially what you're doing is let's say in our case we're grabbing a list of properties we're asking the server to send us the list of properties to the front end so that's where you do filtering searching sorting and pagination this is a very common interview question
a lot of people get asked and the reason why you could do this is cu you know sometimes you just get a small list of uh data and you can do filtering searching and sorting and that's pretty easy especially you have a table it's super easy nowadays you have like data grid material you something I use a lot but they provide options to filter search sort and you know do it all all if you just you just you just do some imports like you just import that and they provide all the ways to sort do
all of the complex filtering it's a very complex process but they have a lot of it built in and that makes us this client side filtering sorting searching pretty easy if you have an application like this uh you won't get those easy benefits cuz you have to do it manually cuz this is like a very custom UI that you have to filter through but in our case we're going to do something called server side filtering and this is where we do all the search sorting filtering on the server instead of the client and when you
do that you send the limited list of data to the client and now this is ideal the advantage of this is good for large scale applications that cannot be really efficiently handled on the client and you have less data getting sent over the network so any application that has a lot of data that you're sending to the client those are the times when you want to think about using server side otherwise you use client side because it's much more easier to implement but this is definitely for higher scale um large scale Enterprise applications which is
what I focus on so I want to take an example of this where you might see something like this in apartments.com let's say you have a section like this and let's say there's a lot of apartments that are getting hidden in this application if you get thousands and maybe tens of thousands of houses or rental units being loaded at one time and imagine how many clients might be doing this that's a lot of data being sent to the front end and it is going to slow down the users's experience because you're sending so much data
so the way to handle that is that whenever you have some some kind of user where they're setting a little you know maybe a minimum rent and the maximum rent they have a very small amount you can make it a lot you can reduce the amount of data being sent so you have something much more efficient so now you see this this is pretty simple there's only a few when you're doing it it sends to back and telling it to say hey this needs to be limited don't give me all the data so my computer
doesn't get overloaded with all the list of Apartments just imagine to the client you send all the list of apartments in uh California that would be crazy that would be too many rental units for Enterprise applications you you're going to have to figure out how to scale that and that is where we do serers side filtering but it is a little more complex and it does put more burden on the server whereas client it would be on the users so you your server doesn't get overloaded but in this case you're going to have more burden
on your own server so there's a trade-off but in certain cases like this even though we're not going to have like millions of users or millions of Apartments we want to pretend like it is and you know have a scalable application that will work so we are going to do a server side filtering and the way to do this is very common practice and a lot of times when you're setting up an application in nextjs you want to store the filter data or basically the state not in react State you want to keep it in
the user uh URL so let's say they choose a search location of Los Angeles as you can see over here and that shows the different latitude and longitude specifically for uh Los Angeles or if you have the minimum price it would be tacked onto the URL query parameters that's how you normally do it and the reason why you do this is so that anytime you send a URL to someone else you're able to share it with other people of specifically URL query parameters and when you do that you add all the filters on top of
it on this URL and that URL gets sent to the back so when you get sent to the backend you're going to extract those query parameters and then in SQL specifically we want to initialize the wear conditions so SQL has these things called U SQL wear conditions which you can tack on a number of filters and queries and qu conditions that we can add and just for your benefit if you want to take a look on what we are actually doing because there's quite a bit of filtering happening in the skl query is right here
so we always want to add favorite IDs you can add that the price minimum price maximum the Beds Bath property type square feet and so on and so forth so we check if it exists like if it has been added here we're checking it if it exists and if it does we're going to add it to the SQL conditions and after that you're just going to going to build the SQL queries with the conditions and we are going to fetch our properties it's pretty simple I mean it looks very complicated I'll show you but it's
a very straightforward process and we're going to be able to do it in our SQL query we are not using and you know we use Prisma for our orm usually it abstracts a lot of these situations but when it comes to something like this where you're doing an SQL query like this it's better to do it raw SQL instead especially when you have geospatial location which is also using post GIS which I'll talk about shortly so that is a properties list which gives us the places based on the filters but there's also a few other
things that we want to take a look at which is this favorite button which also adds more complications let's say we want to add or remove the favorite property mutations we are going to make a API request to the properties backend database and obviously we are going to get the properties list which is also incorporate I just wanted to show you an extra thing so don't worry about that and then also we also want to get the user tenant info because that is exactly where our properties are stored like the users who favored a property
it's basically going to be stored in the tenant but it connects to the properties table so essentially these two are kind of connected in a way these two are kind of connected they have relations basically the user tenant has the ID of the the properties of which that user favored it and that's going to be able to fetch the properties of which one it's favored so pretty straightforward I know this diagram looks intimidating for just some you know what you might think would be easy as a developer but this is probably one of the harder
things that you'd have to experience as a front-end developer or even backend sometimes now this part which we are going to use the location on each property so the location is basically stored as geop spatial you know uh values as you can see with the latitude and longitude these are just numbers that you get from like a online store or online website where it gives you a specific latitude and longitude of specific locations you can uh make API request to ask oh where is this actually located you can send Los Angeles and it'll give you
the latitude longitude and then once you have that you can put that into something called mapbox which is the map use M that we are going to be using all right with that all that said I know it's very complicated but we're going to go through it step by step so hopefully it'll make more sense as we go along all right to start off we're going to open up our server directory go to our source directory and go to index.ts and from here we're going to add another set of routes which is going to be
app.use /properties and we're going to do comma property routes which we have not created and note that I'm not adding off middleware over here because this properties page we do not want the user to be required to be logged in to access this so This API endpoint should be public some of these endpoints are going to be public but some of them are not going to be public and we're going to handle that inside our group as well so we're going to do import property routes from routs SL propy routes like this all right so
from here we're going to open up our properties routes folder we're going to create a new file I'm going to call this property routes. TS I'm going to open this up save it and then in here actually let's go open up manager routes copy everything over here just so we have the boilet plate and I'm going to paste it in here and we're obviously going to change this so we're going to change the managers to property controllers I'm going to change the router to to.get let's just get rid of everything with the colon Cognito ID
and we are going to set get properties and then also we're going to do another one and it's going to be colon ID and this is going to be a get request so we can grab a single property so get property like so and then another one over here is going to be router. post but this one is where we are going to create property and this is the one that we want basically a middleware so we want security for this one so we're going to say o middleware and we are going to pass in
manager only managers can should be able to create a property and this is something will happen a little later and then also when you create a property we won't handle this right now but we're going to have something where we need to upload photos so we're going to just do upload. array photos like this and to do this we're going to go above our router and say storage is equal to molter do memory storage like so and then const upload is equal to molter uh curly braces storage colon storage so this allows us to um
basically upload the photos using molter and we're going to upload it onto S3 buckets later on way later on but for now we're just going to create this so we're going to do get properties from the controllers and then get property comma create property as well and I'm also going to import molter from molter like that so that should be good I'm going to open up controllers and create a new file we're going to call this property controllers. TS and I'm going to open up manager controller just copy everything and then paste it in here
all right so from here I'm going to erase the uh update manager as well as the create manager for now and then just go up to here we're going to change the get manager to get property or properties like that and we going to do everything that we talked about with the property search and doing sorting and all of that good stuff on the back end so I'm just going to remove all of this because I don't want any of that so what we are going to do is we're going to grab a lot of
values from the front end and we're going to be sending this from the front end to the back end and we're going to start with a lot of these values so I'm going to scroll in over here so you can see we're going to start with price Min price Max we're going to skip the favorite IDs actually yeah no we actually want that so we're going to do favorite IDs like so price Min price Max we're going to do beds bass property type square square feet Min square feet Max we're going to grab amenities available
from latitude longitude and we are all going to grab this from rec. query because they're query params I'm going to change the error retrieving properties for the error now from here with the wear conditions we just set up a variable called wear condition using a let variable and we want to type this with Prisma Prisma SQL with angled brackets brackets like that and new comma like this we want to make sure we import the Prisma from Prisma client so we can just do that and to start off we're going to do the favorite IDs so
if favorite IDs exist which is going to be an array of IDs we're going to grab favorite IDs array grab favorite IDs we have to type it as string forcefully and we are going to split this with comma and we're going to do map number to make sure that the IDS are converted into a number and then from there we're going to do aware conditions. push and we're going to do prisas do SQL uh template string we're going to do p ID in pren Prisma dojin favorite IDs array so essentially we are adding to the
wear conditions which is an array and we are putting a template string p in like this so this is basically an SQL query so anytime we do in it's going to check if the P ID exist in this Prisma array or basically this uh favorite IDs array so that is favorite IDs and then from here we just have to go down the list and do every condition and I will show you how to do every single condition pretty simple so if price Min exist we're going to do another one where conditions. push we're going to
do prismas do SQL with template string p with double strings price per month we're going to do greater than or equal to dollar sign number PRS price price Min like so so we're basically pushing p. price making sure it's greater than the price Min that we are getting make sure this is spelled correctly so basically we are grabbing the attribute of price per month making sure it is greater than the price Min we're going to do the same thing we're going to grab this instead change both the Min to Max by doing command D we
change that to Max and change this to less than or equal to and then from here we're going to do deal with the beds and bath pretty simple so if beds and bath or sorry if beds and beds does not equal to any just to make sure we don't have any of those weird conditions cuz we'll be setting that in the front end we're going to do wear conditions. push Prisma SQL we're going to change this right here to be beds so that is a property beds and the number is going to be beds like
that so pretty simple we're just making sure the beds are greater than the the minimum number of beds and same thing with bath so I'm going to change these to be baths like so making sure this one is bath so all the beds and then all the bass all right and then next is going to be the property type let's actually do square feet cuz that's uh more similar so I'm going to change this to square feet Min if that exists we're going to change this to be uh double quotation square feet greater than is
equal equ Al to number of square feet Min I'm going to do the same thing with square feet Max change this to be Max and change this to be less than or equal to and then we're going to handle the property type so this one's slightly different we're going to do if property type and property type does not equal to any we want to do p do property type like so and making sure instead of this number we're going to change this to property type with colon colon string property type and this should not be
a less than or equal to this is just checking if the property type is equal to the property type that we have and this is basically the enum that represents the property type that we have set and last one we're going to copy this one more time this one's also slightly different I'm going to change the property type all of these actually yeah hold on one sec so when we change this property type multiple times I'm going to change this to amenities plural and we got to change a few things we got to add an
amenities array we're going to set that to be amenities as string and then we are going to split this using a comma and we're going to do aware conditions of push but this time we're going to put this in parens actually my mistake you don't need parens we're just going to do p do amenities this one does not need double quotation strings and we want to do at is greater than amenities array like so this will B basically check if any of the amenities is one of the amenities right it's a weird symbol but it
represents that check and the next one's a little confusing I'm just going to go through this kind of quickly I'm just going to copy and paste this one because it's kind of prone for me to get an error or make a typo so you guys can see if available from available from making sure that it's a string otherwise we're going to set it to be null so we can double check that it exists first and then also to check if it's a date we're going to force that into a date and then if it is
not a number or making sure it is a number and the date time actually exists so basically we're just checking the date so all of these are just conditional checks to make sure we have an actual date we are actually going to push Prisma SQL with an exist select one from lease L we're checking where the property ID is and the start date is less than or equal to so in a basically when we do a property you generally have a lease and we want to check the lease that is associated with the property the
lease is a separate table aside from property so you need to fetch the lease information basically this an SQL query Feast you need to check the start date of the lease instead as opposed to the property so this is how we check when it's available from and as the power of SQL queries a lot of relations between tables makes it easy and then finally I'm going to copy this copy and paste this one too but this one is pretty important I'm just going to explain everything so if the latitude and longitude exist so on the
front end we're going to say if someone searches like Los Angeles or you know maybe New York or some some location name we're going to make an API call from the front end which will grab the coordinates of that location and that coordinates are going to be separated into latitude and longitude values and those latitude and longitude values are basically going to be numbers converted to Strings and we're parsing them first into numbers using float which is like a decimal then we're grabbing radius in kilometers which is a th000 we're just going to say it's
a th000 and then you divide it by 111 to convert them to degrees just to make sure we're in the right unit format because there's degrees and kilometers so we want this to be in degrees and then we're going to push this value this is a little bit complicated but store D within we're going to set the coordinates of the location using geometry and then set the SR make point it's a little confusing but this is essentially postgis storing that point as latitude and longitude and optimizing it so all you have to understand is this
is kind of how you do those conditions and a lot of times I don't fully know how to write this code but this is one of those scenarios where you can talk to Ai and say Hey how do I store this information inside postgis because I personally haven't done this so one of those things you would probably ask how to store this all right and then that is the last of all the wear conditions the final thing is going to be setting up the complete Prisma query so again I'm going to copy and paste this
so I don't have any errors it is kind of a pain to write this while I'm talking because sometimes I do make typos so I'm going to paste this this is the entire court now now I will explain so we are going to use Prisma SQL again I guess I haven't explained this but this is how you would do raw SQL in Prisma you under this template string but here we are going to be selecting everything from the properties object P which is property P this is what we identified and we are basically building what
we want returned from the database and the way we want this to be set up is the ID comes from the L the L represents location and location is a separate table utilizing postgis where we have stored the location of the property we are grabbing the ID the address the city state and the country and the postal code of these properties and we are also building another object called coordinates that displays the longitude and latitude of that location now you probably don't need these values the most important thing is having the coordinates cuz if you
have the coordinates then you can convert it into any one of these but we are going to build that object and then we are going to grab that information from the property and then return it to the front and then on top of that I know this looks confusing it's just this part is where we're building what we want to return from the database like an object format of how we want information from the database and we are identifying here where we're getting from because these are like short hands essentially like property P represents like
from P we're building this object we're grabbing the location and then from there we are setting the wear conditions after so the we conditions if that is greater than zero meaning we do have we conditions then we attach where basically it's like right below it's like where you know then we write all the conditions that we created and then we also add another and if there is more otherwise we set a Prisma empty so that represents all the query that we need to grab our data it looks very complicated but once you get this you
know you don't have to do pro uh filtering searching sorting it doesn't happen all too often it is a very U logic intensive part of applications so just know that this is like a very interview type questiones that people ask maybe not server side but client side at least but it's important to understand that this is a very common thing in front-end development where it does take kind of it does does take time it's not easy to make something like this there's a lot of prone to error anyways from there we want to do properties
we can do a weight we're going to do Prisma do dollar sign query raw so this is how you execute now this is just a query so it doesn't mean we actually called Prisma here the execution of the p uh uh Prisma query is going to be in here so we say complete query like so so this is where it executes that action and then we are able to grab the list of properties and then send that to the front end so yeah I know this is quite a bit but this is essentially how you
make a very complicated filtering searching sorting on the server side and then from the front end we just have to send the correct query prams to the back end all right so from there now we can get all the list of properties but what if we wanted to just grab one property now this is also a little bit of an ordeal but I am going to try to make this pretty quick because there's not too much educational value here but uh we'll see so I'm going to grab get properties like I did change this to
get property and we're going to do try like so and inside here we're going to grab let me save this let me do catch error any like so save that so we have correctly formatted so in here I'm going to do const ID is equal to rec. params like so I'm going to do const property await Prisma do property to find unique so we're going to find find the property like so and we're going to do where ID is colon number ID so pretty straight forward for now and then we are also going to include
colon location colon true now when it comes to the location it does get a little bit complicated but it should be relatively straightforward in terms of what is happening so the first thing we want to do is grab the coordinates so we want to do const coordinates we're going to grab coordinates put it in string like so with brackets like that and what we're going to do is make a Prisma query raw here so we're going to do await Prisma do dollar sign query raw and we want to select basically grab as text coordinates and
make sure we have the correct typing as coordinates from string location where ID is equal to property. location. so this is how we are going to fetch it from postgis we are selecting the coordinates basically as text I know there's ST which is their formatting we want to make sure it's as coordinates otherwise we get some issues from location which is the table and we're going to make sure the ID is equivalent to the property location ID that will give us the coordinates of the property that we want and then from here we're going to
grab geojson colon any and we're going to use a function called wkt to geojson this is a package that we installed and this is for formatting and making sure that we are using the right coordinates so we are going to grab the coordinates we're going to dot coordinates like this and making sure that we have a null check essentially there and then we can from here grab the actual coordinates because when you store the values it is not in the right format so that is why we are using this particular package to format it in
the correct way so once you have this do using wkt to go Json we can grab the coordinates via this function and the first one is going to be longitude the second one is going to be latitude and we're going to do goo json. coordinates with one like that and from here all we're going to do is making sure we add property with coordinates we're going to grab all the property values that we had but also just add a location property do property. location so all the location that already exist but also we want to
grab the coordinates because by default the location already exists when we did this but we also needed to add the coordinates because the coordinates are being saved in a different format and we kind of need to do this and the reason why it's saved in a different format is for optimization purposes there is a lot of interesting information in regarding you know storing data there's a lot of technical things that you can do to store in database that makes it all all like efficient and make it work pretty well but we're not going to cover
that that is more detailed about the databases it's in that case but in this case we're just using it to use use it for Best Practices so property with coordinates we're going to pass that to the front end and in our catch block we are just going to copy over here res. status 500 pass that in error retrieving property and we're going to change this to eror like that I know it is kind of confusing it is kind of a pain but all we're doing is just transforming data that we're uh storing like when you
store the location coordinates it is kind of annoying to do because it's not exactly the normal format that we have to usually deal with all right and then the last thing is going to be create property so I'm just going to copy this entire thing once again to make it easy we're just going to remove all of this this should be crate property and this one is kind of long but this one is a lot more simpler to understand so hopefully you haven't I haven't lost you at error creating property like so for the error
all right but in here when you create a property we need images that the user can upload that shows the image of like the property so that is going to be involving direct. files and we are using Express molter do file so that is the molter files that we are able to grab and then from here we're going to grab the address city state country postal code manager Cognito ID and the rest of it is going to be property data so this is all going to come from the front end this there will be a
form we're going to do rec. body like that and just real quick I just want to show you since I haven't shown you but the add new property is going to be the separate you know URL it's going to be a huge long list of forms and there's going to be this image right here where you can add images but we're going to do all of the backend first because it makes sense to the back end all right so going back to it we are going to do photo URLs so this is the part where
we upload photos to S3 now we're going to talk about S3 at the very end or close to the end but we are going to write the code to upload files into S3 because you can't just store the images onto like the node server you want to store it into something like a S3 bucket which is AWS service for hosting files big files like this all right so inside here we're doing promise.all files. map because there's potentially more than one file we're going to do const upload params because when you upload to S3 you need
to set up a few things we're going to upload a bucket and we're going to do process.env S3 or. S3 uncore bucket uncore name we're going to do an exclamation like this we're going to also set a key which is going to be the name under which the file will be saved in the S3 bucket cuz it's kind of like a full structure we're going to have date. now we're going to have another one file. original name so basically this is so we can get um like a unique name for each one and then we're
going to have a body which is just going to be file. buffer so that represents the actual image and then content type is going to be file. MIM type so that is just the upload prams but we're also going to have upload result and we're going to do await new upload and inside here we're going to do client colon S3 client and we're going to handle I'll show you where these values are coming from but then we have prams is going to be upload prams and then over here we're going to do done because this
is a promise and then we are also going to return upload result do location which will give us the URL in which the photo was uploaded now in regards to S3 client that's because we need to initialize S3 a way to connect and we can do that via going up here we're going to do const S3 client is equal to new S3 client and that's going to come from AWS St create client S3 that's why we downloaded it and then in here we just want to set the region we're going to set process. env. AWS
region like so and then also I mentioned we had upload we're going to import upload from AWS STK lib storage so that is another way these two libraries you do need and that should be good for the photo upload right here all the way down all right and you remember how we have basically address City State country postal code basically this is what they're going to fill out on their front end for a user readable understanding of where their apartment or house is located you would have to convert that into latitude and longitude and to
do that we would use something called n no n minute time I I not going to try but this is there's a link in the description you can see how the search API is basically formatting but basically you can put like address City things like that and that will convert it to latitude and longitude and this is free there's like search limits but you probably won't exceed that because we're just using it once every once in a while when we're just creating a new property so we're going to call this create new geocoding URL and
we're going to say https let's actually just copy this guy right here paste it in here we're going to do string like that new URL search prams see if I can open this up a little bit and put in PS we're going do curly braces we're going to put for street is going to be address colon City this is all part of the documentation country postal code this should be low lowercase colon postal code we're going to do format colon Json and then and we're also going to do limit colon one so this will construct
our URL via new URL search forams that basically creates it and then we also want to make sure this is a string at the end of it all and then using this we're going to do geocoding response to grab what we have and we want to import aios to grab the geocoding URL and we are going to pass in a headers and this is just all again one part of what we need for this API you need a header otherwise it's not going to work and I'm going to set here user agent Colin and this
they tell you to write the name of the application that you want and your email something like this like you C you can do whatever I don't fully know the purpose of this maybe they just want more data or something I don't know but you need to put the Heathers or else you get denied and then over here then we can grab both the longitude and the latitude when we do geocoding response. data0 question mark. l n I'm going to do an and something like that copy this paste it over here so this one is
going to be Dot lat making sure they exist otherwise you might get potential errors if it doesn't return anything but in here we're going to do parse float making sure that we convert it into a number I'm going to paste what I wrote and do comma parse float as well paste it in here but change this to Latin latitude or basically L and we're going to do colon 0 0 if nothing is return turned cuz they by default will give you z0 or it's like they'll give you an error and that is exactly how you
get the latitude longitude it's kind of annoying there's a lot of steps to it basically an API call with specific settings will give you it and then from here I'm going to copy this because again this is kind of long prone to typos you can take a look if you don't want to write all of this by the way you can just go to the repo you know copy and paste this page so you don't get any errors with all of this it's up to you um but yeah so the next part is going to
be creating the location I'm just going to comment this create location the location is going to be an object that we want to create into location you know the lo location table so we're basically grabbing the query prams or query raw from the location we're inserting into the location table actually sorry not inserting into the location we're grabbing the location actually my mistake creating a location it is creating location sorry I I got really confused for a sec so we insert into location the address city state in this format so we're going to insert into
location and we're going to pass in address city state country postal code that we created and then also we are going to set the longitude and latitude using post GIS with 4326 I don't fully know but you have to have that specific number don't know exactly what that represents but we are going to return in this format if we want so these are the values we are inserting into our Prisma query and then finally this is where we can actually create the property so as you can see we have to create the location first which
is like an item in the location table but also we need to create an item into the property table as well and we do this by saying new property like so with a weight Prisma property. create and we need to make sure everything is the right format this part is just a little bit tedious but the idea is pretty simple and we're just going to uh extract everything from the property data the photo URLs we want to insert that location ID colon location. ID manager Cognito ID then amenities is going to be type of property
data. amenities we do need to do a check to make sure it's a string in this case and if it's a string we're going to do properties property data. amenities dosit via comma colon empty array like so save that I know that's kind of a bit of annoying but over here we're going to also do the same for highlights so I copied everything do command D for highlights and then over here we are going to do is pets allowed and we're going to do property data. isets allowed is equal to true for default so that's
going to be a Boolean is parking included and you know what I'm just going to copy and paste this cuz I don't want to type all of this I know because there's a lot of typing but just take a pause you can take a look we did is Park get included based on the property value making sure this is a Boolean and then we're also doing price per month which is a which should be numbers all of these are floats floats except for beds that should be an INT as well as square feet that should
be an integer same with bath should be a float and then over here we're going to do include location colon true and then manager colon true like this and then that should be able to create our new property and we do res. status 2011. Json new property and yeah that's pretty much it that's quite a bit I know um let's make sure we don't have any issues make sure those are linted correctly make sure I click that maybe sometimes you have to write two of those and then fixes same with property routes we're going to
do e s like that make sure it's correctly I'm not exactly sure why this is uh showing it it worked in my other application don't know why it's giving an error but it should be fine because the location represents ah okay so this location actually needs to be coming from Prisma client so if you go up here we're going to do import location from at Prisma client so if you do that we scroll all the way down this location ID is correct it was just pulling a location object which was not the right one all
right so we have the get property get properties but there's also one there's a couple property get request that we want which is specific to manager properties we want to be able to get manager specific properties as well as tenant specific properties now this is pretty simple because it's going to be very simple to get property with minor changes so if you go up we're going to copy this entire get property and we're going to go to Let's close all of this we're going to go to manager controller and we're going to put this in
here instead because it makes a little more sense and we're going to go down and paste it over here and this will be relatively simple we're going to change this to get manager property and we're going to change this Rec primes to Cognito ID because it makes a lot more sense when we want to grab Cognito ID and in this case we can just change this we can say const manager is equal to await Prisma do manager. find unique and we are going to use our Cognito ID to find that specific user so again we're
identify Ying each user via Cognito ID and then also with that manager ID we want to do const properties is equal to await Prisma property. find many and we want to do where colon manager Cognito ID is equal to Cognito ID like so and we want to comma we want want to do include colon location to be true as well and then below this we're going to do const properties with formatted locations so basically because we are grabbing multiple properties potentially for the different properties that the manager might have we're going to do promise.all and
I promise after this it's going to be pretty simple we're going to do promise properties. map for each property we're going to do async property like this with an arrow function and inside here we can actually just grab this entire list over here and we can paste it in like this basically we are grabbing the coordinates once again like we did before nothing different we're just going to grab make sure we import that for geojson we're getting the longitude and the latitude we're passing in property and the location formatted correctly except in this in this
case instead of creating this variable we are going to return this like so we're going to remove the if condition over here and we want to uh return properties with formatted actually I spelled this correctly incorrectly properties with formatted location like so so very simple to get property except in this case it's possible that we are fetching multiple properties for specific for that specific manager and you know what we actually don't need this I don't know why I wrote this we can just do property Prisma property find many in a real application you would check
if the manager exists cuz sometimes you might be able to send wrong Cognito ID but we're not going to add all those extra um checks for now because what we already have is quite a bit and then over here instead of error retrieving property we're going to say error retrieving manager properties plural and we're going to save that so yeah so this is pretty simple we will create the route but before we do that let's actually go open up copy all of the get manager properties once again and we're going to go to our tenant
controller and as you can expect we would do something similar like we did before so we're going to paste it and go we're actually going to call this get current residences that's how I labeled it but it's probably better to make it consistent um get tenant properties but this is more so because like a different terminology just because they like rent the place as opposed to um actually owning it so it's a little bit different so in this case instead of this wear condition we're going to do wear tenant colon curly braces sum colon Cognito
ID just to check and get the tenants make sure the Cognito ID for those properties include and then we're going to keep everything the same and we're going to say residences with formatted location I'm going to change this to that make sure we import it correctly and again we just going to change this to residences with formatted location make sure you remove that and that's it so these are these two endpoints are specifically to grab properties for specific users and we needed one for manager we needed one for tenant and we also obviously need to
add these routes so we're going to go to manager controller or manager routes and I'm going to go under here router. getet slon Cognito /properties and we're going to do get manager properties from our controller and that should be good and again none of these routes are going to be or all of these routes are going to be required authentication because we gated those and then we also want to go to tenant routes inside here we're going to do rather doget slon Cognito IDC current-- residence is and then do get current residences from our tenant
controller and then save it so that will be all our routes and controllers to grab grab properties all right and the last part of the tenant routes is going to be these add and remove Favorite property mutations so let's get started with that so I'm going to go to tenant controllers and I'm going to go scroll down to the bottom and actually let's go here copy the get current residences so we have boilerplate and also copy this last part like so so you have that line you can save it and we can say get or
sorry add favorite property like so and then we would say error retrieving manager we say error adding favorite property all right and then inside here we're going to grab the Cognito ID and the property ID from rec. prams and then we're going to do const tenant is equal to await Prisma do tenant. find unique and we're going to do where Cognito ID include colon favorites to be colon true so we do want f from our tenant and we are going to change the property ID number to number property ID it's the convenient variable make sure
this is correct and then below this I'm going to say const existing favorites is equal to tenant. favorites or empty string and we're going to put a question mark and then also we need to check if the person already favored that particular property ID so in this case from the front end we're sending both the Cognito ID of the tenant and the property ID of the one they're favoring so if it's already favored we don't want to do anything we'll just say property already added as favorites so we're just going to say existing favorites. sum
we're going to say fave fav doid is equal to property ID number like so basically if it already exist we're going to do const updated tenant is equal to await Prisma tenant. update we're going to say where Cognito ID comma data colon favorites colon conect NE colon ID colon property ID number so this is just Prisma Prisma syntax where you have to set the connect for the ID property ID number and we also want to include colon favorites to be true and right above this we're going to say res. Json updated tenant otherwise we are
going to send res. status 49. Json and we're going to say message property already added as favorite so basically this is a check just in case they send two calls for the same property making sure that they are not already added so you don't have multiple properties being added or else you get lots of books and then over here we're just going to copy this we're going to do the same thing except oh that is not what I wanted to copy copy this entire guy right here paste it below and we are going to say
remove Favorite property and inside here we're not going to find tenant we're going to keep the property ID number and we're going to do const updated tenant is equal to await Prisma tenant do update we're going to do where call in cognito ID like so comma and see where this data is we can just copy this part paste it over here so instead of connect we're going to do disconnect we're also going to do include colon favorites to be true now all of this we basically don't need anymore we can just say res. Json updated
tenant to the front and then instead of error adding we're going to say error removing favorite property we're going to save that go back to tenant routes make sure we add these endpoints and over here I'm going to do router. poost do slon Cognito ID SL favor slon property ID because we need both of those and we're going to bring in add favorite property make sure that's imported I'm just going to copy this one more time and this should be delete this time and we're going to change this to remove Favorite property and make sure
you don't have any duplicates like that and there you go it is quite a bit for the properties I know but you'll get through it all right so now I would have loved to do the properties front end but the properties is also connected to leases and payments and applications they're all kind of interconnected and now I do want to show you the properties front end but I want to do all the back end first for this section because they're all too connected I don't think there will be problems if I don't do it like
this so if you go back you can see the property is very connected to the application as well as the lease and also the payment so all of them are kind of connected I created a little bit of flowchart I don't know how useful this might be but essentially if you take a look manager has applications that the tenant creates in the application we we're going to approve them and if it if if it's approved then they are lead it leads to lease and then the tenant gets added to the current residences of that property
the manager also manages property which includes both the location and leases and the payments once they have the leases and that will be get signed to tenants so as you can see they're kind of all basically related so we are going to create location or not location uh leases payments and applications for our backend for now I know we are doing lots and lots of backend but I promise you we'll get to the front end if you guys like that stuff all right to start off we're going to start with leases because leases is very
very simple so I'm going to close all of this um and we are going to uh let's start with the controller this time we're going to do lease controllers. TS and we're going to maybe just go to manage controllers copy all of this from the top just so we have boiler plate close this out I'm going to close that but here we're just going to change this to get leases and I'm going to remove everything over here keep the res do status we're going to say error retrieving leases so leases is pretty straightforward compared to
everything we have been doing leases we're just going to grab and await and by the way because the app is already quite big and the property section was so big I didn't do any very detailed um lease things where it's like it's going to do the approval where the lease gets created and you'll have a document I didn't do a lot of that because it's way Beyond scope but we're just adding this just so if you want to increase the scope and you want to include it by all means you can add it as a
stretch feature so when we're grabbing the leases we just want to do tenant is equal to two true as well as property to be true so we can grab the lease as well as the tenant and the property in one go so that's how you do it in um this is how you basically do SQL queries inside Prisma they have their own stuff it is limited though and then from here we have the get leases we're also going to do get lease payments so we we want something specific to grabbing the payments as well and
again we're not doing any payment processing in this application just to keep the scope manag cuz we've already covered so much it it would be too much to do all of that it won't go all right and then from here I'm just going to copy the leases once again but they'll be changed to payments and we're going to do payment dot Prisma payment. find manyu and we're just going to do where curly braces leave lease ID colon number ID like so we're going to do res. Json payments and make sure you don't forget that colon
and there should be an ID like that and then error retrieving lease payments and we're going to save it and that should be good for all our lease controllers I told you it's a lot easier we're going to do lease routes as well to make sure we create this let's go to manager routes paste it over here in the lease routes and we're going to change this up all the way over here we're going to do a slash like this and we're also going to do off middleware we're going to pass this in with manager
and tenant like so so in this case we want both manager and tenant to make sure no one else can get the lease and we want to do get leases as well and once again I'm just going to copy this paste it over here for this one it's going to be colon id/ payments same like this except this should be get lease payments like so and I can get rid of all of this and that should be good for all our lease routes except for right here which you want to do app.use slle leases and
then do lease routes go up here to import lease routes from sure I capitalize that to do SL routes SL leas routes and lease is done all right so the final part is going to be applications now applications are a little bit more complicated than the leases and the payment stuff that we just did because the application is going to be more connected to the property the tenant um also the leases and payments they're all connected and when you update the application you need to update a number of different things and they're all interconnected so
it makes it very complicated but it is less complicated than properties so don't worry we're just going to go through this pretty quick but I'll explain everything as we go so let's create a new file we're going to call this application controllers. TS and again let's actually go to lease controller copy everything paste it over here to make our lives easy I'm just going to remove let's actually just keep one like this error retrieving we're just going to keep it so we can copy and paste this later on but for now we'll start with list
applications like so so this will list all the applications that we have to make our lives easy I'm going to remove all of this inside here and we're just going to say error retrieving applications and inside here we're going to do const user ID user type is what we're going to get from the front end now don't worry about what we are getting from front end because I will explain everything when we get to the front end we're just going to do everything but here we need a wear Clause like we did before and and
we need the work Clause to determine if user is a tenant or manager so we're going to do if user ID and user type exist and also if user user type is equal to tenant we are going add a we Clause of tenant Cognito ID colon string we're passing user ID and also else if user type is equal to manager we're going to set the wear Clause to be property callon manager Cognito ID colon string user ID so basically we're just doing two different conditions depending on if they're tenant or a manager and then we're
we're going to actually fetch all the applications we're going to do await Prisma do application. find many and we're going to pass this in we're going to say where colon where Clause to include it and then include curly braces property colon include colon with location so we want to include the location in our queries as well as the manager as well so we do true and then we're also so going to go below the property like this and do tenant is equal to true as well so we want all those values in our applications so
we can work that out and then we're going to create a function this is a function that I was going to put it into a utils file but I decided I'll just put it here calculate next payment date and we're just going to set start date colon date like this colon date and this all this is going to do is make sure we can calculate when the next payment it is due via the month so nothing too fancy and we're going to also set the today date as well as next payment date is equal to
new date for start date now these are going to be all hardcoded for the actual dates that we set for the payments and stuff like that mostly because well it is too too much scope is too much so while next payments is less than or equal to today we're going to do next payment date. set Monon do next payment date. getet Monon invoke that we're going to do plus one like so and we are going to return next payment date from here I'm going to do formatted applications is equal to await Pro pr. all and
inside here we are going to do applications. map and we're going to map this out with async and an app and we are going to do const lease and we're going to try and find the lease relevant to this property so promise. leas or to the user so find first we're going to do where colon tenant colon Cognito ID colon app. tenant Cognito ID below this we're going to do property ID colon app. property ID and we are going to do order by colon start date colon descending make sure you have a comma and a
comma over comma over here comma over here this should be order by not order by so basically we're finding the first lease and then also we are going to return in the correct format everything in the application property colon app dot dot dot app do property so we're just formatting what we want so we're going to do address colon app. property. location. address comma manager colon app. property. manager comma lease colon lease yeah I know it's a lot dot dot dot lease comma next payment date and we're going to do calculate next payment date to
be lease. start date and on the next line we're going to do colon null and then finally below all this we're going to do res. Json PRS formatted applications all right just to just to summarize what what happened I know there's a lot of typing here we're basically checking if the user ID is a tenant or manager we're going to do something different depending on whether they are manager or tenant so we are grabbing all the list of applications we are then going to grab the lease relevant to the application because there's only going to
be one lease for each application and we are going to format that and then we return it all right so we have that and then we can copy this again for get lease payment and we are going to do create application and now for this I'm going to start copying paste thing because this is it gets quite a bit and I'm just going to grab all the IDS or not all the like the properties right here properties of body from the front end so from the front end you're going to get application date the status
the property ID the tenant Cognito ID name email phone number and message from the body and then from there I'm going to grab the property from Prisma like so using wear ID colon property ID and we're going to select price per month and the security deposit making sure we select those as part of the property and we want to create both the application and the lease in one transaction from Prisma so basically one query so we want to do Prisma do transaction so we want to create both a lease which is what you will see
right here you want to add question marks to these actually you want to make sure since the property doesn't exist we want to add this if property does does not exist we'll just say property not found but basically here we are creating a lease we are setting the start date and the end date now these are hardcoded like I mentioned the start date is today the end date is one year from today we're also setting up rent the deposit connecting it to the correct property and connecting it to the correct tenant and then we also
create the lease and then we want to create the application after we create the lease so we have the application we want to create the application after via this so do create there's a lot of properties we have application date so when the user applied status name email phone number message connecting it to the correct property connecting it to the correct tenant and connecting it to the correct lease now I know that's a lot of pain but this is this is what happens when you deal with SQL and you have a lot of relations and
then after that you want to return the application and then you want to make sure you close this up so in this case we have a new application and we are creating both the lease and the application together making sure we connect the lease to that application and then finally we're just going to return to the front end res. status 2011 that we created it Json new application like so and then we can say error creating application and again if you don't want to write all of this you can go into the repo and copy
and paste a lot of this because it's just a lot of properties that we're just kind of writing over making sure we do that you might get a lot of typos when you do this so all right and then finally with the final get lease payments we can just change this to update application status so this one is about approving or rejecting the application so the manager can approve or reject the applications that they receive from all right so so I'm again just going to copy and paste a number of things because I'm getting tired
of writing this so we start with the ID from recot prams and the status from the body and then I'm also going to grab application from Prisma we're going to make sure we grab that application we're also going to check if that exists if the application is found make note that we are including the property and the Tenant information and also if status is equal to approved we need some conditions so basically when the user gets approved for the application we need to create the new lease so new lease gets created when the status is
approved then we also need to connect the property to to the tenant and then we need to update the application with the new lease ID so yeah I know it's quite a bit so when the status is approved we want to create the lease connect update the property to connect the tenant and update the application with the new lease ID otherwise there's only two statuses by the way approved and rejected so this else condition represents when the status is rejected in this case we don't do much else and we just update the application status to
denied via the status as you can see over here and that's good and the last thing we just want to do is respond with the updated application details for the user and we just want to send that updated application to the front end if needed so yeah the application is kind of quite complicated there's a lot of steps to this but it is what it is when you have SQL sometimes you end up having situations like this and also we want to write error updating application status and with this now we can go to the
routes so let's go to the routes and we need to create a new file we're going to call this application routes. TS and we're just going to go to lease routes copy all of this paste it into application routes and in here just going to remove that one I'm going to keep this to be tenant and this is for create application so only tenants can create an application and this should be a post call so I'm going to call uh copy that add another one this will be for the update application status so I'm going
to change this to colon ID slash status and this one is going to be for manager only because only managers can update the application status and finally I'm going to copy it one more time I'm going to say router. getet and for both manager and tenant they should be able to grab the application so we are going to say list applications for that I'm going to remove all of this and we have our routes fully set up and also we need to set this up in index and I promise you this is the last of
our backend Explorations so SL applications and we're going to do application routes like so and we're going to go up into import application routes from. routes application routes all right so we have finished the back end so that that that was the entire application's back end by the way we covered all of this so we're going to now we can focus on the backend I I will go over each of the backend sections as we go through because you probably will forget what we' have done but I'll just remind you as we go along of
what happened all right with the backend setup what I'm going to do real quick is I'm just going to navigate to my parent uh directory I'm going to do get add. G commit dasm backend complete and get push origin master I'm just going to push this up so you guys have another git checkout that you can use for just just checking if your work is correct all right with that now we can work on our front end so now we can go to Source go to our app directory and go to non dashboard inside here
we're going to create a new folder and we're going to create a search page now this search page will include this search page of this map the top filter bar this listing of properties and the all filters tab as well so it's going to include all of this so there's going to be a lot to cover in this area so let's get to it so I'm going to have the search over here I'm going to create a new file and I'm going to call this page. TSX and I'm going to do rafc and we're just
going to call this search page save that and let's actually open up our terminal and we're going to run both our front end and back end I'm going to run npm runev for a server and then npm runev for a client I'm going to create a new tab I'm going to say Local Host 3000 all right once we're here we're going to go to SL search to make sure we see our search page and there you go we have our nav bar and then we have our search page text over here which is good so
I'm going to close that and we're going to get started with creating this page so the first thing I want to do is I'm going to create a search prams and we are going to do use search prams from next SL navigation this will be used in cleaning up our search prams and grabbing the search prams from our URL and using that to set our filters now it's not relevant right now but it will in the future and over here I'm going to grab use app dispatch this will use any actions that we create in
our Redux state so if there's any functions that we want to run to change our Global State this is what we have to use and then from here I'm going to create a variable called is Filters full open equal to use app selector which is going to come from our Redux State and we are going to pass in state and also state. global. is Filters full open so yes I haven't created this yet so let's see what the purpose of this is for so this date is for the Boolean for opening this filters button like
that so we are going to save that in the global store and it's is very nice to have something like that in the global store because we're going to create a lot of components to make sure our code is clean so you don't have to pass in properties all over the place for component that's why Global store is very nice a lot of people who say uh they they don't need you know need Global store or you don't need a global State well you you probably haven't built the real production level application and make it
very clean code so just mentioning it's probably not something you have done all right so go to your state folder go to your index and inside here we're going to go over here and write export interface and we're going to create a state called filters State now this filter is going to be the typescript interface to represent all the filtering state that we are going to use including location so we've all talked about this before so beds will also be a string baths will be a string property type will be a string amenities is going
to be this one's going to be a string an array of strings available from is also going to be a string price range now this one is going to be a little bit different this is going to be a number number or if default if it's nothing's been selected we're going to say null null we need like a null check when it's empty and then there's also square feet that we want to do we're going to do we're going to just copy this once again so the same exact thing and then finally we're going to
do coordinates this one is not going to going to have an initial uh initial State because we don't want that one to have initial because we always need a number or a starting point for this and then for the initial state so this will be the global store right there's going to be a few things in here that we're going to add first of all it's going to be is Filters full open I'll make sure you spell this correct so that is what's going to allow us to open or close the filter uh the filter
Tab and then we're also going to and actually this should be a comma and actually this is not typescript this should be just false this should be a Boolean and then from here we're also going to have filters which is what we just added over here we're going to copy this but we're going to fill this out to be location by default I'm just going to choose Los Angeles because it's the easiest and then bed is going to be any with a comma and I'm just going to copy the next two amenities is going to
be an empty array available from is going to also be any the price range is just going to be null null so that's the initial with comma we're going to do the same thing for Price or square feet and the coordinates we're going to set is going to be for Los Angeles so that's going to be 8.25 because I already figure this out and 34.5 this should be a comma and we should be good to go for our filters State and the last state that I want to add is going to be the View mode
which is going to be grid this one is just going to be simple it's going to represent this button right here so this one is list this one is grid so that should be pretty fairly simple we're going to keep those as our state and then also we need to type this so we're just going to write initial State types so I'm going to grab this cre create an interface add a curly brace and we're going to say filters filters State like that and we're just basically going to mirror it so so is Filters full
open this is going to be a Boolean and then the last one is going to be View mode and this one is going to be either Grid or List as our potential options so once we have that the state that we want to create is going to be set filters colon State and then the way we type this for the action is we use something called payload action which should come from Redux JS toolkit so we're going to say payload action like that so this is to type our action State and we are just going
to do partial and make sure that n is over there partial should be filters State like so make sure you close that and then we're going to do an arrow function and inside here I'm going to do state. filters is equal to do do do state. filters comma do dot do action. payload like that that's good and then we're also going to have another one we're going to call this toggle filters full open so we're going to open or close our filters State and we're going to do state like this with an arrow function say
state is Filters full open is equal to the opposite is filters and by the way if if you're not familiar with Redux toolkit or any Redux these are reducers but basically you can think of this are actions that change the state I don't know why they use all these fancy terms like this is the problem with Redux when they came out they they tended to use all these fancy words for no reason they're just functions they're just functions that change the state into different Stat or like this different different values that's all all all these
are and then the last one we want to do do is set View mode and as you can see we can probably just copy this over here except the payload action should just say either Grid or list and we're going to do an arrow function like we did before and we're going to do state. viw mode is equal to action. payload like so this should be capitalized and over here all we have to do is resemble set filters toggle filters full open and set View mode once you have that you have the state that you
can use anywhere in your application so that's why when we come back here we can just realize that this has been created it already is typed as you can see global has the initial State types that means this is fully if I change this to something like this it's going to give us an error all right so from here we're going to go to our div and we're going to start changing up our jsx and we're going to do class name is equal to width of full MX of Auto PX of five Flex Flex column
like so and then on the next line I'm going to do style and I'm going to do height colon calc 100 viewport height minus Navar height we're going to bring that back again again with pixel and we are going to create a margin top colon with the string navb bar height so we just want to make sure the height is correctly set and this should be inside and make sure we have a good margin top for the rest of the page we're going to save that and below it we're going to create we're going to
call filters bar like so which we have not created but let's actually create the rest of this page just to make sure we have the right div we're going to say div class name is equal to flex justify Das between Flex of one overflow of hidden gap of three margin bottom of five and we're going to close that and inside here we're going to have another div we're going to put class name name with the height of full overflow of Auto transition Dall duration of 300 we're going to say ease in and out and we're
going to have a dollar sign we're going to say is Filters full open and we are going to have different widths depending on whether the filter is open so with a 312 with a capacity of 100 and it's going to be visible like so so that means when it's open we're going to have a wider width of course whereas if it's not we're just going to give a width of zero with an opacity of zero and it's going to be invisible this will make it so that as you can see when we have this it's
going to open and close like that now over here we also want use client at the top otherwise we won't see anything and inside here is going to be our filters full item so this is what's going to be this the left part of it and the filters filters like that and this will be the filters bar at the top right here and the map is going to be this one and this will be listings so we're going to write those few things so I'm going to say map this will close out like that we're
going to comment that out because we haven't created that yet and then we're also going to start with div class name give it a basis of 4 12 overflow y Auto close this and this will be listings like so so we're going to close that that's going to going to represent this guy and it's going to determine the width it could be more responsive but I limited to this not exactly sure how it would look like on smaller screens but it's responsive enough all right so we're going to start with filters bar so brace yourself
there's a lot of code I'm going to do some copy pasting but I will show you on the screen I'll explain everything as we go because there's a lot of code to right so let's start with filters. TSX in here I'm going to do rafc where we're just going to write filters bar just to see if we have something so I'm going to uncomment that out and make sure it gets imported so I'm going to save that and you should see filters bar like that all right here I'm going to start by adding const dispatch
is equal to use dispatch so we're going to use react again or Redux and then we're going to use router from use router and this needs to be from next snation not next router and then const path name is equal to use path name also from next navigation and then const filters we are grabbing that again from Redux we're just going to say State we're going to grab it from state. global. filters like so and then we are also just going to copy this over here whether F filters full is open or not make sure
we paste that save it and then from here we're going to grab View mode as well use app selector and we're just going to say state state should be state. global. viw mode as well and over here const search input to save our search input as well we're going to keep it like this with use state from react make sure we save that for filters. location in this case we could have added this inside the Redux state or Global state but this is this is only used here for the search state all right so from
here we want to be able to change filter and what we want to do is update the URL anytime the filter selections change so we start off with the function called handle filter change and this will be the main function that we use throughout this section so we're going to do key of A String with the value of any is min we'll be calling Boolean orinal and I'll explain what this is we're also going to use an arrow function and set new value to be equal to Value so in this scenario we're going to say
if key is equal to price range because price range and or key is equal to square feet this situation is very different because these are remember array with two values in them so they need to be tra uh treated different so we're going to start with current array range and set that equal to dot dot dot filters key like so so essentially when we have this function we are passing the key which is if you look back here one of these keys in this case it's either going to be price range square feet and coordinates
or actually not coordinates but one of those and we're just going to make sure we have the current array range as well but if is min does not equal to null we are going to set the index to be is min greater than or it's going to be either zero or one if it is minimum then it's going to be zero otherwise it's going to be one and then we are going to set the array range index to be equal to value of any or it's going to be null number and value and we are
going to set the new value to be equal to the current array range so essentially we're going to have different filters and if it's like the minimum one we are going to set the index to be different values if when we deal with ranges like this because in this case we have any minimum price their index is going to be different depending on if it's the minimum or maximum in those cases and if the value is equal to any we're just going to set that to be null or number of value so it's going to
just depend on those two values we're going to change those and we're going to set those as the new value we're just replacing those values now if you don't fully understand I don't know if I explained that very well but just ask chat gbt or something if you don't fully understand that the other part is a lot more straightforward so let's say in the case it's key of coordinates in this case we're going to set the new value equal to Value if it's equal to any we are going to set this to be 0 comma
0 as a default otherwise we're going to set the value value. map of number and then finally otherwise we're going to set let's actually just copy this part right here this is for all the other properties this is pretty simple if it's a value of any we're going to set that to be any otherwise we're just going to set that to be a value and with that we can say const new filters is equal to pass in the filters that we already have with the new key new value basically we are just adding the new
value with the new key replacing it if we are talking about that handle change and then we are going to do set filters new filters so essentially we are just replacing the Redux State we are changing the filters as we go and then we also need to update the URL so we are saving the current state of the filters in our Redux store but also we need to update the URL as well so we have both instances of state that we can rely on so to update our URL I can do const update URL is
equal to debounce and the reason why we want to do debounce is just so it doesn't it doesn't update too much when we type too fast so we're going to do import debounce from and this should be incur braces from low Dash and then we can set new filters like this with an arrow function inside here I'm going to do const clean filters is equal to clean pams which is something we have in our utils and I'll just show you real quick it's basically cleaning up our prams with any undefine any and making sure they
are clean essentially and then we want to make sure we update the search prams so we're going to say updated search prams is equal to new URL search prams we grab those and we can say object. entries clean filters and then we're going to do four each and we are going to pass in key comma actually this should be in another curly braces we're going to say key value with arrow function like this and we're going to say updated search params do set and we are going to pass in key comma array do is array
with value question mark value. jooin with a comma is equal to value. two string like that and this keeps on changing to key frames it should be key that and then finally below all this we're going to finally put that in our URL so we can say router. push with the template string path name question mark updated search search pram .2 string like so so that should be our update URL and what we could do is you see where update URL is we can pass in new filters and I added filter state for our typescript
make sure you're importing it from Filter State here so yeah we have handle filter change so that is going to be our state changing for any value in this entire filter bar so I will go through and hopefully this will make more sense so let's do that so I'm going to start off with adding some class names I'm going to say class name Flex justify Das between items center with a full py of five like so and below this I'm going to create a comment I'm going to say filters like this and we are going
to say div class name with flex justify Das between items Das Center gap of four padding of two and close it and then we're going to have this is the part where I'm just going to start copying pasting you can take a look what happens but it is a little bit tedious to write all this so I'm just going to start doing so but I'm going to make sure I import stuff so button should come from at component slui button the CN should come from at liia tills toggle filters open should come from at SL
State and the filter is it's going to come from lose side react for this so I'm going to save that I'm going to show you that we have this filters and there you go you can see that we have the all filters button um the one thing that seems to be a problem is that we do have this layout maybe if I take this out actually no no no we probably shouldn't change that we should probably change this one over here yeah yeah I think that's good right here so basically if you go back to
your search page just get rid of the margin top because it's already existing no point of doing that and with this button you can see we have a lot of styling over here you can just look at this and copy it and then we also have our button so that allows us to hover over it so we can see that this is the all filters button and this toggle filters full uh open will change our Redux State all right next on the list is going to be the search location so I'm going to make sure
I import everything else so act components UI and also our search blue side react icon and I'm going to comment this out for now handle location search but you can take a look at everything over here going to zoom out so you can see the extremely long class name maybe I'll just put this on separate lines so you can see better so you go like this so so here we have Flex item center with an input search location and we're going to set search input when we type so we can type anything but right now
we have it by default Los Angeles and then of course if you click this button we're going to have some function where we handle location search we're not going to handle it right now because it's going to involve map box but for now we're just going to leave it like this and we have our button with all of these stylings as you can see all right so from here I'm going to type a few things I'm going to add a comment and I'm going to say price range so this is for both Min and maximum
price so I'm going to start with a div say class name is going to be Flex with a gap of one and then what I'm going to do is I'm going to add the minimum price selector so this is going to be a select dropdown from Shad CN once again make sure I import everything with select value select content select item as well and finally format price value that's going to be a utils function and what you'll see is you're going to see the at any Min minimum price so essentially over here what you're seeing
is that we have a value of filters price. range we're going to grab the first value in price range which is the minimum if you remember over here we have the price range this is going to represent the minimum and we are going to make sure that handle that filter is changed properly and when we say it's true if we go back up to over here in handle filter change we're saying this is true that means it is not null that means we are setting the index so that we can identify which current array range
we want to change so the value in this case is going to be the first index so that's zero if it was maximum it's going to be one and that's how we identify which array index gets changed whether it's minimum or maximum and then over here we basically change any one of these values to determine which one is a minimum price we set the 500 100 things like that but then we format those values and then we also format the price value so later on when we actually use it and send it to the back
end this gets formatted to the correct value this is just how it looks like when it comes to when you do a drop down because it's concatenated but when you use this this is you need to send the proper number or string to the back end and then similarly we're going to have something similar with maximum price selector I'm going to copy and paste it over here so you can take a look over here nearly the same thing you could just copy and paste it just some values that are different like this but most of
it is going to be the same except this as you can see our handle filter change that's going to be false for the price range and make sure you understand that the price range when we set it it's going to be the first index not the zero index all right so from here I can just copy this and we're going to do something similar for beds and baths so I'm going to copy this go over here change this to beds and baths and we're going to change the minimum price to beds and the maximum price
selector to uh bass now when it come to the value obviously a lot of these have to change so filters. bed and then on value change this one is just going to be instead of price range it's going to be beds value and null like that we're going to set the width of 26 rounded Excel keep everything the same for the select value we can just do select value with a placeholder of beds and make sure you close it and the select item we can just actually get rid of the array stuff we can say
any beds and then change or copy all of this paste it over here we can say value of one and we can say one plus bed we're just going to lowercase it because I just like the look of that and I'm going to copy this three more times change each value to two then three and then four and these should be plural so there's a lot of like little tedious things that you kind of have to do with all of this we're going to save it and then I can just copy the bed and then
take the bats and replace it and from here we just have to change a few things so anytime you see beds we're going to change it to Let's actually copy all of the beds over here and change it to baths plural same with over here we're going to change that to be singular bath and this should be capitalized as well I think that should should be good oh yeah this should be capitalized to for consistency and there you go we see we have all of these values the values are correct and the value 1 2
3 4 is the correct value as well and actually there should not be four plus bat 3 plus bat is good enough and the last one is going to be below this closing div I'm going to paste this one because it's tedious but very similar to before we're going to have a property type we're going to have a values of property type if not exist we're going to say any and if the on value change we're going to say property type of value null like we did before the default one is going to be home
type make sure the width is 32 and we're going to select any property type and this property type icons is going to be a enum from at libc constants which is something I wrote before and over there should be be pretty good with the select items that's going to show us different item list for our property types so it's going to have an icon as well as different property types so that is very good and last but not least on the very edge now I know it's not responsive it doesn't close normally what you would
do is um fold all of this but it was the scope is very ginormous and you know this is a video on YouTube so it's a little much already so we have to just create this part which is on the same line so we're going to do that real quick and I am once again copy pasting this so below this closing div I'm going to write this which is The View mode and I'm going to import a few things from set View mode make sure we grab that from redex the list comes from lucide react
as well as the grid also comes from blose side react so all this is doing is just flexing two items next to each other styling them so that they're basically rounded and when you click on them actually let's save it so you can see when you click on them you can see that there's an icon and it will change between those two views and we also have the state being changed with the list versus Grid so we can use that for later when we change it between the different type of list views so there you
go take a look at that if you don't want to write all of this you can again go to the code and just copy and paste it l you have some bugs and issues you can check it out all right with that so if you made any changes like this now you can see that it's getting pushed up into the URL which is perfect this is exactly what we want anytime we make any changes they are all getting added to here when I switch back to any beds it disappears so that's exactly what we want
now when it comes to this filters full option which is pretty similar we actually need to set some local state because this is going to be working differently this is going to have a local state because once we have this we then set the apply button which then gets added to do this so it's a little bit of a weird uh Paradigm but we have a local state that's going to save State over here but it won't change the url right away until we hit the apply button I think this is mostly how most of
these all filters type works so let's get started with this all right so I'm going to close this back up go to our own application and we are going to close this out uh yeah we're going to close that out close this close this and we're going to go back to this page actually I'm going to keep the filters bar open because we're just going to copy a few things over there so I'm going to create filters full create a new file called filters fold. TSX over here and we're going to start with RFC save
that and we can also make sure that gets imported from filters full and save that so when you click on it then you can see that it pops up and it disappears and has a nice little opacity effect so let's start with that so we're going to go over here to the filters bar and we're just going to copy uh all of this right here and paste it in here like that now we don't need the View mode or the search input but we are going to create the local filters that I mentioned so local
filters set local filters and we are going to say use State we're going to grab it from react and we're going to say initial state. filters like so so we're going to have all of that make sure we import use app selector use dispatch use router actually that should be from next navigation and used path name should also be from there now this initial State should actually come from the Redux state so we're essentially creating a new separate initial state of filters inside our local filters and we're using the same exact um state and from
here we also need a few functions like update URL we're going to use the same exact one I probably should have put this in the utils function but it was a little bit late I didn't realize you know I probably should have just done it before but I'm going to import debounce from low Dash and we're also going to import filter state from our state as well as clean prams from our lib utils and we should be good and then also we're going to have another function called handle submit so this is going to be
where you hit the apply button and we're just going to do something very simple we're going to do dispatch set filters to be what local filters represents and also we have to just update URL to be local filters so we're essentially setting those filters to be the filter in our state we're taking the local state filters and setting it in the global state so once you hit apply it gets applied globally as well as well as a URL and then handle reset is going to be something similar we're going to set local yeah set local
yeah yeah set local filters we're going to set initial state. filters like so we're going to set dispatch set filters and we are going to set initial state. filters like this and then also update URL to be initial state. filters so basically there is a reset button that essentially resets everything this one will reset everything for our entire state and then finally just as a double check if is Filters full open if that's not true we're just going to return null like though all right so inside here we're going to close this open up this
I'm going to say class name is equal to BG white rounded large PX4 H full overflow - Auto padding bottom of 10 inside here we're going to do div class name of flex Flex column space y of six so they're all spaced evenly of Gap of six and now from here I'm going to once again start copying so you can take a look at the code or go to the repo to copy and I'm going to paste this so again we need to import input from our Shad CN components as well as at our button
we're going to comment out handle location search because I'll get to that and the search icon like this so when you see that you're going to see the search button similar to this like we saw before it's basically the same except to set local filters will be the main difference and you might see it gets a little cut off but it's okay and then from here we are going to then use property type the property type looks a little bit different so let's go where the location finishes which is right here I believe actually there
should be two closing divs and we will paste all of this so property type like this and we want to import property type icons from our constants as well as the CN function from our uols and what this is going to do is going to list out with icons and the property type with different stylings we're going to set the local filters when we change it similar to how we did it before and you can see that we have our icons and you can select each one of these so it's a little different from property
type that we saw here it's just a different shape this time and then from here we're going to be using the slider from Shad CN as well for the price range again since it's all filters this is like much more advanced version so if we save it see let's just change this to any the slider needs to be imported from act components you I and if I select this you can see that we do have a slider now that slider is not styled properly but take a look let's write this out and I'll fix that
this has an H4 for the price range the slider is going to involve a value with an array for the low part and the high part via the price range remember that is an array with two values in there and also we are putting the text below these values for the spans and then the sliding just needs to be adjusted so right now as you can see there's only one slider and you can't see any kind of bar below it we we want looks like this we want it to have on the inside something like
that and the values changed based on on the sliding movement so we have the low one but we do not have the high one so we can go to our Shad CN you can actually instead click on slider you do alt or command click to go to it instantly like that and what we want is if you see here BG primary we want this to be 700 and then we also want let's close this a little bit we're going to grab this guy right here copy it paste it over here and voila as simple as
that you'll have a price range going up and down similar to what we had before so everything is perfect pretty easy shats end sometimes is nice if it's a simple change like that oh and it seems like like we have this uh low Dash save types that we did not install so I'm going to close out my client directory or client server run npm D- save-dev at types SL L Dash I'm going to install that so we don't get that error and we actually need to retry that we're going to say Legacy dasp DDE PS
like so and with that the warning should go away so I'm going to rerun the server so I can see it I'm going to refresh the page just so we can see it again and open it up so we have our filters once again with no issue all right and then we're going to continue so we have most of this we have the price range like this going to close this out little bit and we are going to add a couple more next on the list is going to be the beds and baths so this
one is very similar to what we had before style a little bit differently make sure you import the select and the triggers and the value as well as the content and the item like this so very very similar to what we had before in the filters bar just styled a little bit differently you're going to see with beds and baths like that so pretty straightforward so you can just pause the screen if you want to type all of this out and then from here I'm going to go down two closing divs later I'm going to
add square feet so that's going to be another slider very similar to what we had before you're can copy the copy and paste the price range and just paste it below as square feet with the min max except change it to square feet so that should be pretty simple again you can pause the screen copy and paste if you want and then below this is going to be amenities so this one is is similar to the property type I believe let's actually add amenity icons from at lips Conant we're going to add a label from
components and then format enum string that's going to come from at lib utils but this handle amenity change is something that we are going to create so again let me open this up so you can see take a pause with this write this out out on your code and we are going to write our handle amenity change function so I'm going to go up all the way and in this one we're just going to have a separate function for this so we're just going to write handle amenity change and it's going to be set local
filters with everything that we already have in the filters except for amenities we're just going to make sure if if it includes it we're going to remove it otherwise we are going to add it so it's a little bit you know like a little cheat code that you have to make this a little bit easier but it should do the job and once I save it you're going to see that amenities all these icons pop up and you can just choose which ones you want selected all right we're getting close so two closing divs again
space we're going to do available from so most of this is right here this time with input with onchange set local filters we're going to add all of these and we're going to have something with available from using an input of type is equal to date so this allows us to choose a date that we want and then finally we are going to have the final apply and reset buttons finally So Below this closing div we're going to add these values and these will all basically be set for us and it should work as expected
so now if I do let's say I choose one of these choose a square feet like that and I hit apply you didn't see it but it shows you the air conditioning as well as well as the square feet that we changed if I hit reset nothing it should all go back to normal all right so we handled everything there's one last thing about the uh initial filters that we need to do is when you come to the page you want the initial filters for the search to be all cleaned up and properly set for
our Global state so we are going to go back to the search page the default search page and we are going to add a use effect in here just so we don't run into some weird bugs you kind of need this otherwise you're going to run into weird errors of the previous filters kind of getting in the way so inside the use effect we're going to have a variable initial filters and what we're going to do is do array. from grab the search perams that we initially wrote do entries so we grabbing the entries we're
going to reduce them do reduce and we are going to pass in an accumulator we're going to say key comma value with an array function or Arrow function and we're going to say if key is equal to price range otherwise key is equal to square feet we always need to clean this because that one's kind of an array we're going to say we're going to to grab that particular key value we're going to split them via string we're going to map them and we are going to set them to V is equal to empty string
with null colon number with a V value make sure you have enough closing print and we're going to say else if key is equal to coordinates we are then going to do ACC key is equal to value.it once again with a comma do map place in number or else if it's anything else we're just going to do key is equal to value is any like we've done before there's probably better ways I didn't spend too much time with the logic here there's probably better ways to clean a lot of this up so it's not as
crazy but we're going to return ACC and we are going to do comma array object or empty object to create initial filters as our object and what we are going to do is clean those filters clean filters we're going to say clean pams initial filters make sure we import clean prams and we are going to dispatch set filters with cleaned filters like so make sure we import that and put an empty array and we're just going to do yes lint that disable dline with react hooks exhaustive DPS sometimes I don't like that warning because sometimes
it's just a little bit annoying in this case we don't we always want it to trigger and save that and we should be good for our filters to work properly with the exception of the location search which will handle with the map and there you go that is all our filters it is a lot of tedious work I'm telling you this is very tedious and I understand that doing something like this you might be wondering oh there must be an easier way well guess what there there really isn't this is just you're going to have
to use a combination of AI and just using your best knowledge in terms of doing all of this it's a very tedious effort um it's not easy either like some people might think oh because you have ai this can be easily done but you can use AI you're going to run into a lot of bugs if you do it that way especially for something as complex as this but we have managed the complex filter system now we do need to connect it to the back end but before we do that we're going to get the
map and we're going to get the listings so let's do those all right so the next thing is going to be this map so this map is pretty nice I was able to customize it into styling that is matching this application which is kind of like a very desaturated color along with a lot of black in the color with a lot of white as well with some nice little blues that are not overpowering so I was able to create this and match the Styles and customize it very well um I used mapbox but I want
to give you some other options if you really want to but they are are limited in other ways so react leaflet is the one that people talk about in a lot of developers is you can probably do something like this but I don't know how easy it is to style this um in a very nice way so this is kind of the problem with something like react leaflet but you can use it it's way it will probably be easier way easier than using something like mapbx but then there's also Google Maps which I think it
will be probably hard I haven't tried it um there's probably packages where you can use like react Google thing like that the only problem with Google is like it always looks easy but something something about it always makes it difficult I don't know why it's always ends up like that which I'm not a fan of but you can probably change it to a decent extent but I think the most customizable one is going to be mapbox which is the one we're going to be using now fortunately it is free now there is price and might
scare people but if you are most likely not going to get to the you're not going to get pa uh you're not going to be charged because in my case you have like 50,000 loads I've only used probably like at most a 100 loads just to do the application but unless you're doing a high powerered you know like lots of users type application you're most likely not going to run into those issues you pay as you go but there's so many requests that you can get for free so it's only like the the pricing is
targeted for large businesses but over here you want to just sign up sign create an account all right once you have created your account you're going to be seeing this page uh we can ignore everything but we can go to style editor now we can create a new style or we can choose like one of these classic templates you can choose all of these different pretty cool looking styles with different settings and such but what I want to do is Click find inspiration in the style G Gallery so that will make our lives a little
bit easier so we can go in and we can select one of these I can probably choose one any one of these Styles but um I think maybe I did Moonlight style I'm trying to remember which one I chose and maybe we can choose something like this minimal this looks pretty cool we can just do add to your studio and basically we see something like this um we can just view later you can see something like this this is pretty nice it's a little uh a little uh UNC colorful monochrome so if we want to
go we can change maybe we can go and see land water and Sky water and we can change the water to be something like this this is actually pretty cool and you can see that we have a lot of editing options I know it's a little overwhelming if you just want to change a few things you can but maybe this is good enough this is probably good enough we just want a little bit of blue a lot of white I've already have my own setting but maybe just a little bit more blue like that and
once you're finished you can you can play play with it to your heart's content but there's so many options there's even like 3D versions you can do and we can just ignore everything we can just say publish and we can go back hit Styles and then we have minimo all right so we'll keep this in our back pocket while we do our rest of it so I'm just saying mapbox makes it very easy to customize and it makes it very nice a lot better and you can see even in the images there's like 3D versions
that you can use if you want to and having said that let's actually go um go over here you can do Public Access token we're going to copy this so I'm going to copy this and we are going to be using this in our EnV don't try to use this in V variable I'm going to definitely cut this um API out after I finish this application so I'm going to do mapbox access under _ token in our. EnV and we're going to set equal to the value I pasted so again that comes from the homepage
that we had we can copy the default public token and then paste it over here so we can use it so once we close that I'm going to close the filters as well but now we can start creating our map finally so we're going to create a new file we're going to call this map. TSX and do rafc and save it make sure we import that so we can see what we have save that close the map and we should be good so for us to use the map and we want to add markers we're
going to need to use use ref all right so mapbox you can find Link in the description I have stuff like this where we where they tell you how to create mapbox GL in a react application by the way we are using mapbox GL which is like the newer faster version of mapbox which is really fast compared to a lot of the other map tools that's why this is very good we can use that and we can connect it to our react but we do require using things like use ref which is not ideal for
a react application but in this case it's pretty simple so we're going to go over here and by the way I am not sponsored by mapbx it's just something I decided to use and from what I read this is like the um Enterprise way for mapbox so map container ref we're going to use use ref for something like this and inside here we want to pass in null and above here I want to add mapbx gl. access token and we do need to import mapbox we installed this a long time ago GL from mapbox DGL
and we also want to import the stylings by default that comes with mapbox you can do this via these two lines so gl. CSS that should be good and the access token is just going to be process. EnV dot let's go to our EnV variable so we don't mess it up grab this EnV variable base it over here and we can say as string like so and then what we're going to do is we're going to grab the filters and we're going to say use app selector grab that from our typescript and we're going to
say state with an arrow function say state. global. filters so we're grabbing the Redux State filters and we are also going to grab is Filters full open we're going to say use app selector because the size of the application or the map is going to be dependent on the size of the screen which is dependent on the filter being open we're going to have Global is Filters full open all right and then below this now what we actually need to do is be able to grab our properties now this was a while we went back
to our server we can see that we need to grab our properties so get properties all the way back here we want to grab this these set of properties all the way and so the way we do this is we need to create an endpoint in our API you remember get off user that was a long time back same with update tenant settings inside here we are going to write property related endpoints and we need to fetch our property from our API so we're going to create those first so the first one we just want
to do is get properties and we are going to do build. query like so and we want to grab property from Prisma types put in Array with partial filters State like so and favorite IDs question mark colon number like so and I know I'm kind of jumping around we're going to close this we're going to put an array and an object but over here we're going to do a number of things we're going to First grab the query like so and I copied this let's make sure you import filter State we're also going to import
clean prams like we did before and we're going to add all the location price Min beds bass filter bath something like this square feet all of that we're going to return the URL Callin properties and pass in the prams as properties so that will finally finish our API call and we also want provides tags and the reason why right now it is not it is is screaming at us we want to make sure we have the result with an array we're mapping the list of arrays like so with type of properties and if there was
already a result we're going to do this otherwise we're just going to have it set like properties ID list and it's screaming at us because we don't have any tags for properties so we would say properties like this and going back to it we should be good for now let's continue I know this was quite a bit but this is essentially sending all the prams that we created from the filters and we're also making sure they are attached to the correct tag of the properties and then we can finally use that endpoint for our front
end so we're going to use use get properties query like we did in mention before and then finally we can go back to our map and I can do const data colon properties is loading is error and we can just grab use get properties Cory make sure we import that and pass in our filters so let's actually just test this before we do anything else so I'm going to do that save it oh open this up and I'm pretty sure it's the error we get is cuz we are not using use client like so so
let's refresh this and let's do console and as you can see we have our list of properties fortunately it works perfectly and we'll double check the filters if that's working a little bit later but for now we want to go on and create our map in here we're going to grab use effect because this is how we want to do map box we want to do an arrow function and we just want to do if is loading or is error or properties does not exist we want all these n null checks we're not going to
return or create a map otherwise we can do const map is equal to new mapbox gl. map we're going to have in parens and curly brackets we're going to create a container with map container ref. current we're going to put an exclamation like so and this is all part of the documentation we are going to do style now this style is something that you have created in your map box so if you take a look over here you can go I didn't mean to click that but over here in your style editor you can basically
grab the style URL you can copy it and then you can go back and paste it over here and we're going to hit comma we're going to set Center and that's going to be based on our filters coordinates or if it's not there we're just going to do negative 74.5 comma 40 this is basically Los Angeles and we're going to set Zoom of nine I just set the default to be there you can set it to whatever you want and then we also want to do return this is just for clean up we're going to
do map. remove like so and we're going to invoke it and below this this is where we can write our GSX so we can actually render out our map so I'm going to start with the bases of 5 12 so that's like how wide of a fraction of the entire screen this is going to be with grow relative and rounded Excel and inside here I'm going to create another div and I'm going to create more class name let's say class name is equal to map Das container with rounded D excl with the ref is equal
to map container ref a style of height colon 100% that should be in strings and then width should be 100% as well and we are going to make sure it's a self-closing TCH and it seems like we have an extra div over here so I'm going to save it and let's see if it worked oh nice we have our map our Map works perfectly and the sizing is as we expect and it grows just like that now let's see when we hit all filters it does refresh to page which is very good and there we
go there we have our map click it it resizes okay sometimes when you see that what's happening is that we actually need to forcefully resize it fortunately there's a way to do that we can say resize map is equal to an error function we do set timeout we're setting a timeout for map. resize it's going to be 700 milliseconds and we can do resize map so you need something like that because it doesn't resize it automatically if I go like this then it resizes it after 700 seconds kind of a hack a little bit I
don't like the solution but it does work all right so we have this but if you look in the final application there is these you know little pin points which shows the location of each map and if you click on it you can see there is locations of our real estate there's no image but we'll take care of that so over here let's actually start creating our property markers So Below all of this I'm going to create a separate uh function and I'm going to just copy this over so I don't have any errors so
this create property marker oh let's actually import this first from Prisma types so this create property marker is going to create a marker in mapbox GL and that's going to have a set longitude latitude so you basically grab the property that we have grab the coordinates longitude and latitude that we mentioned before so we just need the longitude latitude and then we can set a popup as well that popup resembles what this is referring to so this originally sets the location of these markers which is perfect because we have the marker right here and this
popup is what's going to pop up when we have you know when we click on that property it shows the name then it shows like the value and whatever customization we want and we can do this via set popup with new mapbox gl. popup set HTML and then we basically write div it's not formatted like it's not uh linted correctly but it does the job we have div class marker popup marker popup Das image and these are classes that we are already having in our Global CSS when you copied it over and if you just
take a look at all of this I'm going to zoom out so you can can see um maybe it might be better if I just put this on the next line so you guys can see what's happening so something like this would be more appropriate can save it we have an a tag that allows us to click on the property name goes to a different page for this we haven't created this yet but it's something we'll create and then we have a paragraph tag with the price per month and slash Monon and this is all
Dynamic so it's quite cool now we created this property marker but we have not instantiated it so underneath map what we want to do is we want to grab the properties map that we fetched from our backend so we're going to do properties. for each grab each property and then we're going to do an arrow function like so and inside here I'm going to do Marker is equal to create property marker and we're going to pass in property and map as well and then from here we also want to do Marker element is equal to
marker. getet element so we want to grab the marker we want to do path is equal to marker element. query selector this is like old fashion good old JavaScript faction uh grabbing the elements we're going to set the path to be Phill is equal to uh this hashtag 3F B1 c e this is a hardcoded uh color value and we're going to grab that path and I'm going to set path. set attribute Phill 0 0 Z 0 so six zeros like that so essentially what we're doing is we're changing the color to be black and
as you can see once I save it the colors are there and when you click on it you can see that that little uh marker works perfectly and this is very very cool all right and that's it that's our that's our map map box is pretty nice you can have different styles you can have multiple Styles and change it the way you want to which is the most coolest part there UI for changing the map is pretty nice in comparison to something like the other ones I don't think you can customize it to the same
extent and also right here I just want to do a few last things if is loading we're just going to return something like this loading just in case and then also normally I would make this a little better but again a lot of work to do all of that so I'm going to return with div failed to fetch properties like so I'm going to save that as you can see it gets adapted when we close it we can see that we have all the locations perfectly set and our map looks pretty cool to me all
right with that we're almost there we're almost almost there with this page I know this page has been quite quite the tough one and I did not expect it to be this uh challenging for this page but it is what it is all right and by the way is Filters full open we never use it so we're going to erase that we're going to go back to page and we're going to do the final part of the listings which is going to look like this which is the listing of all of these items and we're
also going to be able to do different things like this as well as favorite and unfavorite so now there is these uh notifications we'll take care of that a little bit later but let's start with this um the ADD and favorite buttons so we need to set up the API for those first so we're going to go to our api. TSX and then below this we have property related endpoints we actually want a separate section we're just going to call this a tenant related end points because only tenants can add or remove favorites for the
uh locations or properties we don't need managements to do that so we're going to do um add favorite property and this time this will be build. mutation so this one was build do build. query for the get properties this one is build. mutation and we are going to grab tenant from our types that we added from Prisma types which is very very useful and we are going to grab Cognito ID colon string property ID colon number and we're going to grab that from an array and pass in object inside here and we are going to
do query like so pass in cognito ID because that is what's going the function is going to have Cognito ID as well as property ID like so and we're going to have an arrow function like this with an object we're going to do URL template string with tenants slash dollar sign Cognito ID slash favorites SL property ID like this that is our URL that we're going to hit in the back end we're going to have a method of post for our query and finally we are going to invalidate tags now before we add provides tags
this is going to be invalidate tags now in Redux tool kit query what that all that means is that for an existing tag for example Le when we add favorite property we want to make sure that the tenant and the properties are fully updated anytime we click this button so anytime we click this we want the updated version of the tenants and the properties to be included on the front end so it's going to make a separate API call on top of adding a favor so if I add this favorite it's also going to retrieve
the new list of properties back to the front end just so our data on the front end is fully updated this is a very important thing because sometimes other tooling don't have this functionality so that means you have to make an API request after this to update the new list of properties so in this case for a mutation call it's very very useful and the way we invalidate both of those is we put an array one of them is going to be tenants and we're going to have an ID and we're going to say result
question mark. like that and we're also going to have another one we're going to say type colon properties and we're going to say ID colon string with the list capitalized so that will update both of those properties so that's quite good and then remove Favorite property is going to be very similar and just remember I know it didn't explain that one more time but tenant controller add favorite property was this end point for the controller which is tenant routes we're basically hitting this guy right here this router. poost is going to be this add favorite
property build. mutation we're hitting that URL tenants Cognito ID uh favorites property ID the tenants comes from by the way it comes from this right here just as a reminder so that's how we are hitting the end point so again I'm going to copy this add favorite property but this will be remove Favorite property so similarly will be just like this one but it's going to be a delete so instead of the method post this is going to be delete over here and everything else should remain the same so it's pretty simple and I'm going
to save that and one last thing is just for organization purposes update tenant settings is also part of tenant related endpoints so I'm just going to add that over here I cuted it out does not do anything but it just organize it but over here I'm going to do use add favorite property mutation make sure you use the intellisense to guide you because it already creates it so there you go you can now use these functions that make the API call so now if I go back to page. TSX now we can start creating our
listings page so I'm going to just put this over here listings we have not created it so let's create a new file in our search and we're going to call it listings. TSX I'm going to do rafc and listings like that save it and and then over here I'm going to make sure I retype it so I can import the listings page and if I look at my application you should see the listings over here and I think this is fine we'll see if it continues if it if this continues to pop out it just
seems to happen in development so if I refresh the page you shouldn't get that error yeah it seems like a problem when you save it all right so for that error actually I went back and uh corrected it it's because if you go to map. TSX you go over here I missed a dependency array and what you want to do is add is loading is error properties filters. coordinates so it has restrictions on its dependency array and so when you do that it should be okay now maybe there might be some weird issues sometimes those
warnings are not the best so we'll see if it happens again and we'll try and fix it if that happens all right so from here we're going to go to our listings and we're going to say data colon o user so we're going to grab the user information like we normally do and if you remember use author we go back you can see our Au user object includes user info what we want is the favorites in our user information so that's what we are going to be focusing on and also on top of this we
want to do a few things we want to grab add favorite so again we're using the mutation call like I mentioned before add property mutation like this so in this case we are putting it in square brackets unlike angle brackets when you use a fetch call mutations require square brackets and the first one is going to be the function that triggers that API call and same thing with remove favorite and we're going to do use remove Favorite property mutation make sure we grab all of those and I'm also going to grab View mode from our
Global State using use app selector we do state like so with state. global. viw mode and then we're going to do filters like so using use app selector and we're going to pass in state with state. global. filters like that and then from here again we grab properties and we can do is loading is eror and we can do use get properties query with our filters object and making sure you import so again you can grab the get properties and again it's not going to do duplicate call Redux toolkit already knows how to handle that
so it's only going to call it if it's not already cached and then finally we are going to create a function and this is the function that's going to handle that favorite toggle that we've mentioned for a while now so this is going to be an async function where we are having a property ID passed into this function which is going to be a number and we're going to check if uh o user does not exist we're just going to return just as a null check but is favorite we are going to grab o user
and grab the user info and grab favorites and do do sum and we are going to say fave colon property which is grabbing from Prisma types and we are basically going to check if the favorite ID of the thing that we selected is equal to the property ID we're just going to check if there is a favorite that already exist in the user's favorites list and if it already exists so is favorite we are going to make sure we do remove Favorite we call the function that removes the favorite from our back end and so
we need to pass in cognito ID off user Cognito info. userid and we're also sending property ID like so and just as a reminder if we go back to remove favorite property the query involves Cognito ID property ID so this is what needs to be sent to our back end so that is exactly being passed from that function to the back end and we also want to do else meaning if it's not favored then we can do add favorite like so and we're going to do Cognito ID colon we're going just copy all of this
once again paste it over here and that should handle our handle favor toggle and then from here we're just going to have some if checks we're going to do return something like this loading like that and we are also going to do an error check just in case properties return div filed to f fetch fetch properties like so sure you have that and below this we're going to do a class name we're going to have a width of full inside here we're going to have a H3 tag say class name is equal to text small
PX4 font dasb we're going to close that and we are going to do properties .length so that's going to show you how many properties there existed and then from there we're going to say give it a span class name is equal to text great 700 we're going to say font dormal and we are going to say places in filters. location so it gives you a little bit of a description of what's Happening eight place places in Los Angeles which is good we don't need this listing anymore we're going to say div class name is equal
to flex and inside here we're going to do div class name with p-4 with the full close this out and we are going to have a list properties question mark. map passin property with an arrow function and we are going to set View mode if that's equal to grid remember we're going to show different things so we're going to show let's say some card and then colon we are going to have another card another card like that so if you take a look right now there's we haven't created these cards but in these cases we're
showing different cards based on which ones selected but now we need to create these cards so let's do that so these cards are going to be in a separate page because we're going to be using this card quite often throughout this entire application so I'm going to create a new file I'm going to call this card. TSX and inside here we are going to do RFC with card and it's going to include a number of things so we are going to do property is favorite on favorite toggle which is the function show favorite button in
some cases we don't want to show the favorite button and we are also going to have a link to the property so we are going to use card props which is a typescript that I've already added so you can just use that so you don't it saves you time from writing it and also we want to create an image for this as a backup if you saw before my card basically has like a placeholder backup image and the way to do this is going to be like this so at least for now before we get
to the point where we use S3 we're going to have a placeholder image that we can place over here and we can say or slpl holder. jpeg like that all right inside our card we can do a class name like this background of white rounded Excel overflow Das hidden Shadow D large with a full margin bot of five now this part's kind of tedious so I'm going to do a little more copy pasting again you can go to the repo to copy this so I'm going to do class name is equal to relative and then
from here we are going to do the image part so inside here I'm GNA paste this image make sure you import the image from next image like that and as you can see we have the image source which is going to come from this state property name as well settings for the class name and sizes and just in case if the image is broken then we set image source using placeholder jpeg which is an image I already have in the public folder if you copied and pasted it and then right below this closing div we're
going to paste another thing and this is just going to show the is pets allowed right here in this image right here at the bottom left if parking is included it's also there too so let me close this so you guys can see a little little better of what I wrote and then also below this closing div we have this show favorite button so in some cases we're going to hide this favorite button so it's pretty simple and the button itself is going to have some positioning where it's positioned to the bottom uh bottom right
to the right side with a cursor pointer and on click you have a on favorite toggle function that we are passing along with the heart and the heart is going to have different colors filled depending on if it's favored it or not and then below this I'm going to have another div say class name is equal to padding of four close this and I'm going to have just a little bit of a name pretty simple the div of or sorry h2 tag with a link over the name so next slash link is where you want
so that should be there and then below this is going to be a P tag with the property location and address with the city so P class name text Gray 600 margin bottom two property location address and property location City below this P tag I'm going to have another div we're going to do class name is equal to flex justify between items Das Center close this up and inside here we going to show the ratings as well and again you have to import the star from loose side react and below this we're going to have
a horizontal line like that and finally this will show some extra metadata about about the property and we want to import those from loose side react as well back path and then house like so so right now we do have the cards so let's actually import that so for Su card we're going to change this we're going to do card close this out and we are going to pass in a number of keys to this so we're going to say property doid property is going to equal to property like that and then is favorite and
this is going to be dependent on the tenant so tenant so o user. userinfo do favorites. suum and we are going to pass in favorite colon property like we did before we're going to say fa. D property do ID and if that doesn't exist we're just going to say it's false and then from there I'm going to say on favorite toggle and we are going to pass in that handle handle favorite toggle function that we created earlier and we're going to pass in property ID using show favorite button as well and we're just going to
make sure o user exists we're going to do property link is going to go to this page we haven't created so it's going to be search SL property. ID and as of right now the reason why I have this problem is because I imported the wrong card so make sure you import the card correctly import card this at components slash card and we should have no problems so we should open this up and select the grid and as of right now we get invalid Source prop and that's because of nextjs I wish they just had
this on by default they probably should it's kind of annoying to deal with this but let's open this up we go to next config.js and we want to write our config options over here we're going to say images with the curly braces remote patterns colon in an array we are going to add protocol call in HTTPS like this host name colon example.com because that's just the URL that I have for the mock data Port should be colon empty string with path name colon slashstar star and save that and once that's done you can see that
we do have our look gri there's some issues it seems so we can fix that yeah let's go back to our card and I think I misaligned a div it seems like that's always my problem so let's do that and it seems like if you go over here there's four closing divs we can just cut out one go above here you see where the closing show favorite button is we should add that over here and that should fix everything and as you can see we have all our cards and let's actually see if this works
now it seems like it does kind of work I tested this out if I hit the button nothing happens but if I do refresh the page you get this thing over here but it's because I kind of messed a few things up now what I want to do is I want to go back to listings and things like this happen I did try to make um o user grab the favorites list but it's actually better to do this in a separate API call so what I want to do is use a use get tenant query
API call instead to update this otherwise we're going to have a lot of Downstream issues so right now as of it it works but the invalid validate tags does not update the auth user remember I told you invalidates the tenants and this is my mistake it invalidates tenants but it doesn't invalidate the user itself the user logged in which is what we're using we're using this one so this one is not actually getting invalidated I could invalidate this one but it might pose some weird issues so I want to change this and create an API
for get tenant which is an API endpoint we already created on the back end we just need to create it on the front end so this one's actually pretty simple so I'm just going to go over here where it says tenant related endpoints and maybe I'll just grab this's actually grab this entire thing make it easy this should be get tenant and instead of property this should be tenant of course and this one is just going to be a string is what we are going to be sending to the back end if I save it
it's going to reduce a lot of this the query is going to be a lot simpler so this one's going to be property ID we're sending property ID to the back end and we are using it to make the API call do Properties or sorry tenant and this should be cognito ID closing friends tenants slash dollar sign Cognito ID and over here provides tags is going to be result Arrow function with an uh curly braces type colon tenants comma ID colon result question mark. ID that is what we want to this is the end point
that we want to deal with this will make our lives a little bit easier we're just going to set use get tenant query like so and do comma and go back to our listings page and over here right below our o user we're going to do const data colon tenant and we're going to do use get tenant query and we're going to grab it now what I'm about to do next is a little confusing but it shouldn't be too bad as it's pretty logical Cognito info we're going to grab the Cognito ID and we do
that by grabbing the user ID like this if you remember correctly and we need to make sure that um there's a default value which is an empty string that means it probably wouldn't work but just in case this doesn't happen but realize that these are not synchronous it doesn't mean like this will happen one after the other because these are both asynchronous type calls but you can make it synchronous in terms of using skip the skip means that o user question mark. Cognito info mark. userid that this API call will only be called once the
Cognito info user ID exists so basically when the Cognito ID is fully fetched that means this API call will happen so you won't have any um concurrency issues when making API calls so that solves a lot of problems this also means that we do have to change some of this which is off user user info we want to actually use this with tenant question mark. favorites so tenant has a property called favorites and that represents the favorites list that the user has and finally one last thing is if we go over here we're going to
do tenant question mark favorites question mark and I believe that should be good so let's cross our fingers refresh the page and it's already been favored and as you can see now it fully updates so if you can check on your network call once we hit this button we are sending a request let's open this up we're sending a request to our backend we are sending the favorites which ones are favored and we are getting a response but this one also is fetching another list of properties this list of properties is updating the entire list
of properties just so everything gets updated so if I hit that button we are sending multiple API requests to make sure everything works now it does seem like you could probably end up making this a little more performant but most people are not going to spam click these buttons so it is not going to burden your server too much so you don't have to worry about that all right so then from here we have the card and then this one's going to be a more compact card so let's get to that that should be pretty
similar to the card component that we created so if we go back here I'm going to close this up it a little squishy um we are going to create another component in here we're going to call this compact card. TSX and inside here I'm going to grab everything in our card component copy it paste it into compact card and we're just going to modify from there because it's pretty similar but slight differences so first off I'm going to select both of these you see these two buttons this will allow us to to select the top
two and then we're just going to do compact card props I guess this has the same props so card compact props my bad it should be card compact I don't know why I called it card card Compact and that means we need to change this to card card compact for consistency purposes so a lot of these things are the same except there's going to be minor differences such as like adding Flex h40 over here for the styling the width is going to be 1/3 over here then I'm going to remove this div like this because
I don't need that and over here we're changing the bottom to to left two Flex the gap of One Flex Dash column we're going to change this one to W fit we're going to move pets allowed we're going to say pets parking like so I'm going to take this show favorite button cut it out create another div over here called class name with width of 2/3 padding of four Flex Flex Das column justify Das between and close that inside here I can then paste this guy over here but I'm also going to move a lot
of this and I'm just going to paste it up here and make some modifications so this div is going to be erased or you're going to erase the class names I'm going to do div class name with flex just justify Das between items Das start like so and we are going to surround this around the H2 and then we can move the show favorite button inside that closing div now again if this is too much you can just copy and paste what's happening from the code base so we have what we want over here with
the property link but this button needs to Beck change so we're just going to change this to BG D white rounded D full padding of one and over here instead of this being five this should be four margin bottom of one text of small over here it should be Flex item Center and should be text SM instead of justify between we can remove all of this put it outside over here because we don't need that extra div we're going to change this with and H3 like that mL of one everything is good get rid of
the reviews um and this right here this P tag should be at the very end inside this div and there should be a closing div let's remove one of the closing divs at the bottom and Surround it right here with the number of reviews and when you see this HR we should remove that Flex justify between item Center everything is good let's just remove this text small and we should have another div inside here we're just going to say class name with flex gap of two text gray- 600 close that with the closing div surround
that in the span and actually remove this closing div that should be around the P tag and save that this should be text XS text is base over here font bold with no margin bottom of three and then we're just going to select all of these -5 to be -4 and all these mr2s should be oops didn't mean to do that so or these should be be mr1 we don't need these values over here square foot and we concate SL Monon to m o and let's see let's see how this turns out because I don't
know if this is correct right now and we do seem to have a bit of an issue we deleted a span accidentally save it oh and then for forgot we got to go to listings and we got to add the compact card so I'm just going to copy the card over here same like that except we are going to do card compact import that and everything you pass in could be completely identical and as you can see it looks pretty good but it does have some issues no that looks pretty good that looks pretty good
so this one ALS so you should be able to save and unsave it a little cut off and some of the responsiveness is a little bit tasking I was going to do a lot of that but the scope was again out of control for this application so we're going to stick with that it looks pretty good on desktop and most people would use this on the desktop so this looks pretty damn good to me and again I know there's a lot of issues with the styling so best if you go to the re and copy
this page if you want so you don't have any issues or else you just get a headache trying to like copy it correctly all right there's one last thing I did actually forget is this filter search bar because we got the mapbx everything all set up so let's actually do that right now so if you go to app non dashboard search and if we go to filters full we can go over here and maybe under handle amenity change we can do constant handle location search and close that up we're going to do async Arrow function
like so we're going to do try and I'm going to do const response is equal to await and for this we're just going to use a fetch call to make our lives easier we're going to do https api. mapbox.com slash geocoding SL V5 mapbox actually slash mapbox do places and we are going to encode URI component we're going to do local filters. location and within here we are going to do Json question mark accessor token dollar sign like this we're going to do process. env. next public mapbox accessor token and we are going to do
and fuzzy match is equal to true so this will make an API call to API mapbx and the documentation is all there once we get that response we're going to do data is equal to await response . Json and we are going to do if data. features and data. features. length is greater than zero we are going to grab the longitude latitude data. features Z do Center and we're going to set the local filters grab the previous values and inside here we're going to say preve coordinates colon LNG comma L and over here we're going
to do catch error like so just in case and we're going to do console. error and we're going to say error searching location so basically we are trying to just get from the location which is like the address values we want to grab the latitude and longitude from those values and then from here I want to close this up and I think I may have made a mistake when it comes to closing that that should be good and then the error should just be like that and we have our handle location search make sure you
have a double end over here and make sure you close that so we have our handle location search and that is going to be applied to the search button right here so we are going to go and find our handle location search which is in location and we're just going to do it like that and then we also want to basically copy this yeah so this essentially grabs our location grabs the address from mapbox you can call it from mapbox you can call it from no manim the other one that we did it doesn't matter
each one works and we also want to set this in filters bar as well so below maybe hand handle filters change we're going to set handle location search over here and we're going to do the same exact thing with a few slight modifications and again you can probably just have you know like make this less or more dry by creating this into a utils function but we're not going to do that we're going to do set filters do location colon search input and we're going to do coordinates colon LG comma lat so we're modifying this
a little bit and we're going to close it like that and over here in the eode URI component we are changing this to search in put and we are going to save that and we're also going to go down to the search location and uncomment on our onclick for handle location search so that should be good and with that the hardest page on this application is completely done we have complete filtering you can filter based on price and everything works and you can see that in our uh URL things are changing everything working we have
you know filters like this we can favor and unfavor it we have different views and all of the filtering Works connected to the backend and just realize this is a pretty rough thing for even front-end developers and back in developers there's a lot of moving pieces and it can be quite can be quite challenging and it's a lot of work there's a lot of areas where things can go wrong so pat yourself on the back we'll continue working on this page but this or continue working on the rest of the app but this part was
probably the hardest part of the application all right so as you can see with the URL it's basically search slash the ID of the property so the way you do this in nextjs we're going to create a new folder we're going to put it in bracket and put ID like that inside here we're going to create a new file we're going to call this page. TSX and I'm going to close this up and call this RAF CE and we are going to call this single listing like so and if we want we can check over
here this should take us to that exact page single listing and we should be able to see what we have over here so now to grab the ID we're going to grab it from you use pams which you get from next navigation and grab it like that and we are going to grab property ID from number ID like this so we're just putting it converting it to a number pretty straightforward and over here I'm going to do data colon o user and we are just going to grab our user information once again so we can
use that at a later point so to start off we're going to create image previews so over here we are going to create a component called image previews we haven't shown it just yet but over here we are just going to create an array and we're going to pass in two images single listing to. jpeg because these are one of the images in our public folder and another one single listing -3 JPEG and we we are going to self-close that and that should represent this entire thing where it goes to two screens just like this
now we're not going to have list of images for each property we're just going to have hardcoded images just for the sake of simplicity so what I'm going to do is I'm going to save that it's going to error out but we are going to create a new file call this image all right this page is pretty straightforward we're going to do rafc image previews and inside here we are going to pass in images which is what we just did in the previous page and we're going to do image previews props pass that in and
we are going to say current image index and Set current image index like so and start with use state of zero e all right inside here we're going to do class name and we are going to set a string relative each of 450 pixel with a width of full I'm going to remove this image preview text and we are going to map out our images so map image comma index with an arrow function and inside here we're going to do div we're going to make sure we close this div so we don't have any issues
and inside here we are going to set this to be key with the index or image with class name is equal to Absolute inset Z transition Das opacity duration of 500 ease-in-out and we are going to do uh dollar sign curly braces index is equal to current image index if it is we're going to set opacity to 100 otherwise we set opacity to- Z we're basically making an image Carousel pretty simple one too image from next image we're going to do source is equal to image and then we're going to set the alt is equal
to property image index + one for the alternate text with fill priority is if it's the current index with class name of string object Das cover cursor Das pointer transition transform duration 500 EAS in out and we'll do a self closing image tag like so and then from here I'm going to create a button and I'm going to do onclick with handle previous and we're going to do class name of absolute left zero top 1/2 transform with negative translate so this is just to position it on top Y2 background primary 700 background opacity of 50
padding of two rounded full Focus colon outline Das none Focus colon ring Focus colon ring- secondary D300 I know that's a lot and we are going to just do ARA D label equals previous image and we are going to close it and inside here we're just going to add a chevron chevron left from blue side react and say class name is equal to text- White make sure we self close that save it and then we can copy this over here and we can just say handle next and change this to Chevron right easy enough and
let's actually see our page and it seems like we need to add use client and that's something fine actually if we go to use page we actually need to use it over here because single listing is requiring used prams and image previews actually is not being imported so make sure you import it by clicking that and as you see we should see our supposedly lovely image preview but we did make a little mistake this is WR zero and there we go we should have both our buttons for our image preview and it looks pretty good
all right next up we're going to create another div below this image we're going to do class name is equal to flex Flex column medium screens we're going to do Flex row justify Das center with a gap of 10 MX of 10 MD w-23 MD colon MX Auto mt16 margin bottom of 8 we're going to close this up and over here I'm going to add another div we're going to do class name with order-2 this is for responsiveness and order-1 for larger screens inside here this is where we are going to create a component called
property overview and we are going to pass in a property ID so that that property overview can access the ID value that we get from use prms so from here I'm going to create a new file call this property overview. TSX inside here I'm going to do rafc with property overview and make sure we import that from the page and also we want to add the property ID with colon property overview props like so all right so from here I'm going to do this pretty quick I'm going to grab property so data colon property is
error is loading and then we are going to grab it from use get properties query we're going to grab that from our API calls and we are going to pass in property ID and it seems like not use get properties we want to do singular get property and I'm not exactly sure if we created that I don't think we did so if we go back here we can see get properties we do not have a single get property query so let's do that we've already built the backend endpoint for this we just need to create
the front end so over here I'm going to change this to get tenant copy that over here so we can use that as a template and do get property build do uh query right here changes to property like so which we already imported and the value we're passing in is going to be a number and inside here the query is just going to be an ID the properties is going to be the endpoint slash ID over here and then provides tags we're going to choose result comma error comma ID because we need the ID value
and we are going to pass in the ID like this as well as property details so this is individual property now this tag does not exist so let's actually go up here and add property details so this is specifically just for individual properties if we take a look we have our get property and then we just want to go down do use get property query for our API call and then we can go to property over View and our get property query should be okay now now over here we just want to do a couple
if checks for loading so we're going to return loading dot dot dot and then if is error and we are just going to check property does not exist we are going to do return and say property not found something like that keep it simple and we're going to Fresh it see if it works okay so over here we have our div we're going to remove the property overview text and now we can do a couple things now from here I'm just going to start copy pasting because it is a hassle to do all of this
you can check this out this is going to be the main title section the overview section that we have nothing too fancy a couple of divs with styling and then H1 tag with our property name some loose side icons for the visuals with display of the location and from there we're going to have the number of reviews as well using lucide react we can just pass this property overview with the numbers and save it like so so we get something like this actually this is hardcoded so we probably just want to do property location like
this country state and city like this can do something like that United States California Pasadena so that looks pretty good let's just call this header like so and then from there we're going to have another one and we're going to say details so we are going to paste this again a lot of divs a lot of things about monthly rent price per month I'm not going to write all of this once again because it gets quite tedious especially at front end we can save it and see that we have kind of like a box border
looking like that displaying all our information and then for the last section of this part is going to be summary and we are just going to paste this it's a lot of text you can just put whatever text you want you can just make this short I put this hardcoded value just so it looks better but otherwise your property. description should be long enough to make it look proper cuz if I just took out experience like this if I took that out you'll only see this so it doesn't look that good I'm just adding it
just for the sake of making it look nice and there you go that's it for property overview and we're going to go to page. TSX and we're just going to add property details so this is just more information we're just spreading this out so we don't have a huge component it's up to you on how big the components you want to make but we're just going to create a new file call this property details. TSX and then over here we're actually just going to copy property overview entirely and paste it over here and just pass
in the property details actually should be named property details we can save that and then from here we can make sure we import that so inside here pretty much everything in here is not going to be relevant however the top part is going to be relevant for us so property overview props this should be property details props we can remove those Imports and we can keep everything like this for now and inside here we can say class name is equal to margin bottom of six inside here I can add the top section which is going
to be the amenities so let's actually comment amenities and we are going to show that we have all of this this is a constant so we're going to import that help Circle comes from lose side react and format enum string comes from our library of utils so if you take a look we're just going to see a number of boxes with our amenities something we have seen before in our card components nothing too surprising there and then we are going to do something similar for highlights like this I'm going to paste this over here make
sure we import highlight icons like so and you should be able to see very identical to amenities that there's a highlight section that the user wants to highlight about their property and the final thing actually let's close this up after two of these closing divs is going to be the longest part but this is where we have the tabs section and I'm going to paste this as well and we're going to go through it real quick so we are going to grab tabs from our components UI tabs that we've already installed same with the list
make sure you're not choosing the radx UI same with the tabs trigger and same with the tabs content and and basically we have fees and policies and it does seem like we are missing a closing div I think if I do that maybe I think I am missing a closing div at the very end so I'm going to do that and basically you're going to see these tabs shown like this so we're essentially using Shad CN with a number of Heathers a tabs list with three different tabs trigger so pets working like so and then
tabs content is going to represent each of the pages depending on what you click so value required fees is going to show all of this information like right here the application fee security deposit and then to see if pets are allowed parking is not included in this case so it just depends on what the values are so pretty straightforward I'm going through this fast because a lot of this is very minor UI stuff nothing too intensive just tedious work and I'm going to go back to our page change the property details and it's going to
be property location so again one more thing so we just have different split of the page so property location. TSX and once again we're going to go to property details copy all of this paste it in here for property location and we are going to Select Property details change that to property location save that move over here add the location make sure it's imported and go back to property location and we can just basically take everything inside our divs and erase it and for this page we are going to have once again the map the
map represents over here this is just a very smaller view of the map and we're going to be doing the exact same thing with that value so if you go back we open up our page we can go to map. TSX and we can actually just grab the map jl. access token because we're going to be using that once again paste that over here and then also we are going to grab the use effect everything in side here and pass it into our property location and then from here we're going to make sure we import
everything and get rid of all the stuff we don't need so I'm going to grab that and then do import mapbox GL from mapbox GL like so and I'm also going to import the CSS like this map out G GL d/ mapbox GL CSS to get the same styling we're going to import the use effect and this should be singular property because the previous one was different make sure we have the used effect and actually I realized these if conditions need to be after the use effect we also need to create the map container ref
using use rff as well pass in null inside and that should be good for that we can keep the same styles for this and this time instead of filters. coordinate we are actually going to just set this to be a PRS properties property. location. coordinates. longitude comma same thing once again but this should be latitude and the zoom we're just going to set it to 14 to make it longer so here we do not need extra properties like this but instead if we go back to map we want something from here we want this part
map box gl. marker to set the main marker inside here so we're going to keep it like that and while we don't need the properties up for each we we do want something like this where we grab grab the element change the color of it we're going to close this out and in this case we do not need to resize the map because like before we're not actually changing the map size this time so we're going just remove that as for this none of this exists so we're just going to do property instead we're going
to save that we also want to add iser is loading so it doesn't scream at us and inside our div this is where we're going to change a few things we're just going to say py of 16 and we're going to add a number of things so the first thing is going to add is an H3 tag for the tit title map and location and then all of the subheaders right here so with a map pin we're going to get a loose side react bring that in to display property address and then also compass from
loose react for the get directions and then finally this is where we can actually put our map container rough like this and once we save it and in this case we're going to need to refresh it go down you can see that we have the map and location but for some reason it is not displaying and that is because if you go back up here for the mark we actually need to do a function add to map like so once you do that you can refresh it and you can see that we have our marker
right there and it looks really really nice so as you can see it's pretty very simple you could probably like make it more dry and have this in a utils to create the map things like that but it's not too necessary you might want to change a few things CU it's different from the other one but it's up to you and then finally we need the contact widget which is just going to be this right here that's where you can submit an application so we're going to go back to our page. TSX and over here
we're going to create a div we're going to say class name is equal to order-1 with MD order-2 close that and we are going to add a contact widget like so we are also going to add something called onopen modal we're not going to create this just yet set is modal open to be true but we are going to create the state over here we're going to say const is modal open actually yeah is modal open like this and then set is model open we're going to say use State pass that in with false like
this now over here we are going to create another component contact widget. TSX in this case we're just going to create a new one contact widget like this save it and then we are also going to pass contact widget over here save that we're going to have an issue with the react props so we're just going to say on open modal say contact widget props pass that in and we can now do a number of things we can say data colon o user and we're going to do use get Au use Query like this and
then grab router from use router from next navigation and we are going to do const handle button click so this is to open up a model that we will take care of a little later when we do applications so if o user exists then we should allow the user to open the modal so if you go back to the final application if we submit application they should be able to see the application otherwise if they're signed out right now they're signed in so you can see that if they're signed out they should be redirected to
the signin page so over here we can say else router. push we're going to to force them to go to the signin page and inside our contact widget we're just going to remove the text once again and start writing class name is equal to background BG white border border primary 200 rounded to XL padding 7 H fit Min with three 300 pixel like so and over here let me just fix this so you guys can see close this up and have it like that and from here I'm just going to copy this so you guys
can see this is like the contact Section contact property like so we're going to pass in a phone blose side react icon and then below this we're going to have the big button and this is going to actually be using from Shaden with the handle button click with different text depending on if they're signed in and then finally we're going to have like a horizontal line and the text below for this I'm just going to hardcode it um you could change the language we don't have that or by the appointment date which we don't have
either so we're going to save that and if you take a look we should be able to see that we have this contact widget which is good and if we close it we should be able to see that so right now our submit application won't do anything but we will be adding that once we deal with applications so there you go with this individual page we should be quite good it just looks it's just a visual thing not the most intensive part of the application all right so real quick I'm just going to close all
of this what I want to do real quick is open up our terminal I'm going to close out our front end go back to the Parent Directory close out our back end as well and I just want to do git add dot just so you guys have more git checkpoints and I'm going to say front end or no properties UI complete the most of the property section where we search and individual properties is going to be complete and we're going to do get push origin Master going to go back to client and then oops CD
client and then run our client as well and run our server as well once again all right so from here we're going to do some simple Pages now so nothing too fancy we've already set up a lot of the groundwork if we go to the dashboard for a renter like a tenant person we're going to have the favorites page so this is basically just a list of the properties that the user has favored it we already have the endpoints for this so this should be super easy and then also residences same thing this is the
residences that the person has uh is a part of and then also the individual residence page now this is going to show some lease details payment methods and the building history so a lot of UI stuff there's not going to be a lot of functionality for this it's just going to be some UI things that we want to display so let's start with favorites so we're going to open up we are basically finished with our non dashboard finally and now we can finally finish up in our dashboard so in our tenants uh folder we have
our favorites we already have this page set up maybe I did this on screen I'm not exactly sure if I did this on screen I might have accidentally done it without recording but by the way just add favorites with a page. TSX in your tenants folder and we should we can start from here all right before we do the favorites page I want to create a couple components that we're just going to use throughout multiple files so I'm going to create a new file I'm going to call this heather. TSX this will be the Heather
that we'll be using on multiple CH Pages it'll make our lives a little bit easier so we don't have to rewrite this every single time so in here I'm going to do title subtitle colon or Clos this colon and then header props like so and inside here we're going to do class name with margin bottom of five we're going to remove that header and write H1 class name with text is equal to text extra large font semi bold close this out and we're going to do title like this and then over here in our P
tag class name is going to be text is equal to text small text Gray 500 margin top of one close this out and do subtitle and by the way just heads up when you use reuse components A good rule of thumb is if you're using a component maybe three times then you can create a component so you can reuse it a lot of times some people do it for like two components but sometimes it's just not worth it you should only do it when you reuse it quite a bit in other cases you would just
create separate components it's actually not a big deal sometimes it's only when you know that you're going to change that component a lot and you know you're going to reuse it that's when you want to create a separate component all right so we have our header component there's also one more file we're just going to do loading component and I probably should have done this a while back but this loading component is going to be just like a more a better looking loading you know loading indicator for our pages so over here we're just going
to do class name we're going to do fixed inset d0 Flex gap of two items D Center justify Das center with a background or BG background sl50 so this will place it in the middle and we're just positioning the loading thing and the Loader 2 icon comes from loose side react and it's a pretty cool trick this loader icon is just kind of like a small like a loader spinner thing and all you have to do is rotate it via animate Spin and it looks like a very nice little loading thing that works for basically
everything if you ever don't want to customize your loading animation for everything this is a very nice way especially if you just need functional UI and with that the loader is going to be on the left side font D medium will be on the right and text primary I'll probably show you what this looks like at some point and we are going to say loading dot dot dot so we have Heather and our loading component we're going to close that and and we can work on our favorites page so in here we are going to
do const data colon off user use get off user query and grab that in now if you remember we are going to go to our and I only want to show you because just to remind you what it looks like is if you go over here use get tenant query we want to grab the individual tenant query and paste it over here so we're grabbing the tenant like we did before so we update it correctly and then from here we want to grab the users's favored properties and this time we're going to do favorite properties
we're going to use the same endpoint but there was a point where when we were grabbing the list of properties we are sending to the back end a list of favorites and that was part of the API C so let's do use get properties query but we do need to pass in the favorite IDs and we can do that via tenant Quest mark. favorites questionmark map and we are passing in fave colon ID colon number so this is a typescript thing the only thing about typescript it just makes it look very confusing and I kind
of don't like doing that while I'm teaching it so so favorite IDs we're grabbing the favorite IDs we're passing in all the IDS into this query and we also want to do skip we want to make sure tenant favorites exists so we're going to grab this and tenet favorites. length is equal to zero so if there's no favorites we're not going to call this or if the favorites doesn't exist we won't call it until then so again use get properties I just want to show you one last time controllers property controller we have passed in
the favorite IDs so this favorite IDs is going to add into the conditions so we can fetch the properties relevant to this user all right remember we laid all the groundwork before so it is a lot easier now so is loading and we can do return loading so now we can just bring this in and we can show you what that actually looks like let's actually just I'm going to put this with the exclamation and it should show you what it actually looks like so actually let's go to dashboard and it seems like we are
on the page we're just going to do use client once again sure refresh it and there you go you can see so that is basically just an icon spinning around round and you can see how easy it was to do with this loader to an animate spin which is part of Tailwind so that is perfect but let's get rid of that because we only want to show that when it is in the right time over here I'm going to set if error we're just going to do return div error loading favorites so I got no
tricks to make that look nice we're just going to keep it simple for that over here there is a class name that I did create myself dashboard container so it's just going to give us some margin so if I just add that you can see there's a little bit of margin it's already created in the global. CSS nothing too fancy and we're also going to add a header from at components slhe header I'm going to close this and I'm going to I'll make sure I import that first actually it's already there never mind so over
here we're going to have a title we're going to say favored properties in string and a subtitle in browse and manage your saved property listings save that and as you can see it's all formatted correctly and we can reuse that all the time and from here we're just going to do some you know layout stuff which is grid and grid is good for things like this I know people like to use flex for listings like this but grid is actually better for scenarios like this just trust me on it if you can use grid for
that it is a lot better it makes it makes responsive design easier you can just do something like this grid columns 3 Excel would be grid columns 4 with a gap of six so by just doing that you have a responsive design and it works on multiple screens inside here we're just going to list favorite it favorite properties do map we're going to list the property and we're going to do an arrow function and just to be lazy let's actually go back to listings page which is in search listings we can grab the card over
here which is what we want and we are going to paste over here didn't mean to open up all of that so key property ID this is good for is favorite we are just going to set this to be is true or uh sorry true because it all of these are going to be favored by default on favorite toggle we can just pass an empty empty function because we are going to set the show favorite button to be false in this case we don't want the user to be able to favor or in unfavored here
we don't want them to do that here and then we're just going to say tenants residences and then property ID and make sure we import the card from the correct uh component so not the UI card just the regular card that we've created and then also we need a condition just in case if we have no favorite properties otherwise it's just going to confuse the user you want if the favorite properties is equal to zero and you want to make sure that you show that you don't and then the way you do a apostrophe sign
over here is an an sign posos semicolon T have any favored properties and if we save that we should see we saved two favored earlier and it's working perfectly and we see the cards we didn't have to recreate the cards which is very nice perfect so now we're going to do the residence Pages which is very similar except it's just going to be a different different API call so I'm going to open up over here I'm going to create a new folder I'm going to call this residences inside tenants so I'm actually just going to
copy this page into residences because it is quite similar there will be slight differences and I'm going to close this out so you can see and in here we are just going to grab the favorites and change this to residences like so and inside here these two are the same but this get properties is going to be different and instead of use get properties query we're going to need a API call to grab current residences of the tenant so we have the end point but we do not have the front end to call that endpoint
in the back end so I'm going to open up our api. TS and we're going to go to tenant related endpoints and we're just going to do get current residence actually let's just copy the get tenant paste it over here and we can do get current residences and what we are going to receive is going to be a property with an empty array and a string and we are going to do Cognito ID with tenants Cognito ID SLC current residences for the endpoint now for the tag it's going to be a little confusing but it
should be similar to something we've seen before which is get properties so we want to just grab the tags for all of this and replace the provides tags over here this is going to be the same list of properties so it is exactly the same as before and then we're going to scroll down and we can just say use get current residences query comma so that should be straightforward and then now we can go back to our res reses page and then we can change this to instead of being get progress Curry we can do
use get current residences query like this and in here instead of this being an object we are going to do o user mark. Cognito info mark. user ID or empty string so we need to pass Incognito ID to the back end and we also want to make sure we skip it until we get this value on the front end so like this and we should change the favorite properties to current residences and we can say error loading favorites it should be error loading current residences and below this we can change our title this is going
to be current residences the subtitle should be View and manage your current living spaces so these are places where you have basically rented and living potentially living there so here we're going to say current residences. map now most of this is going to be the same except for is favorite so instead of that being always true we're going to say tenant question mark. favorites. includes Pro property property singular ID or false and you know what it doesn't really matter all that much we're going to change the favored properties to current residences and we are going
to change actually these should be capitalized and you don't have any current residences like so and from my understanding this uh this user right now does not have any current residences because there's no applications the user that I'm signed in has no connections to any residences from my understanding yeah if you refresh it you're going to say you don't have any current residences and I guess yeah for some reason I guess I thought that would work okay it seems like n lsq semicolon T I don't know why the other ones worked or didn't work so
that should just show an apostrophe because you you can't put the apostrophe singular at least I don't think I'm maybe I'm tripping but yeah so that is the current residences Pages now I I won't show you we'll add the residences later I'll show you how it will all look for now this is good enough now let's go to favorites and we can actually see or actually let's look at the final application if we go over here we go to the favorites pages and you can see this entire page this is for an individual residence page
and we're going to be creating this real quick so let's do just that so we're just going to click over here so I'm going to open this up close all of this and go to residences folder and we're going to create a new file or folder called ID inside here I'm going to create a new file called page. TSX and over here I am going to do RAF CE and call this residence singular like so all right so before we do this page there's a couple of more API calls that we need to make so
we're going to go to our API file once again and we're going to add those the first one we want is going to be get leases so go all the way down here at the bottom I'm just going to set lease related end points and we're going to CB uh let's go back to get tenant copy this because this is a very good example and we just need to do get leases like this build do query we're going to do lease in an array like so and the least actually needs to be imported from Prisma
types again that is super useful I'm going to remove this query like this and inside here this is going to be a string of leases for the provide tags we are going to change this to be just an array with leases which we have not created and this should be a number so to do this we're just going to go up all the way to the top and add reles over here and then we're also going to add payments because we're going to do another payments request so we're going to go down all the way
over here and I'm going to copy this get leases and down here I'm going to change this to get payments and this should be pretty simple as well this should be instead of lease payment and that should be from types Prisma we're going to give it a number and over here we are going to say lease ID and we are going to create a template string with leases slash dollar sign lease ID like this with payments and provides tags is going to be payments like so and below this we're just going to say use get
leases query comma use get payments query we're going to go back to page. PSX and we're going to be start adding a lot of this all right so from here we're going to do const ID and we are going to grab it from use perams from next navigation so we can use the ID of the current property then we're going to grab o user so grab the current user do use get o user query grab that and then we're also going to grab the property relevant to us so property like this is loading colon property
loading with error property error like so and we are going to do use get property Cory with number and ID inside so that will get our individual property information but also we need to grab the lease information as well so so we do that let's actually put some space data relases is loading colon relases loading like that we're going to use get relases Cory grab it from our backend and inside here we're going to do parse int because this time is going to be a number instead Cognito info before it was a string but in
this case it's going to be a number so we're going to do parse int and we're going to pass in the zero if nothing is found and we are just going to copy this right here because we're going to do once again skip skip is pretty useful for sequential API calls like this situation we're going to wait till we get the user ID if needed and pass it like that and use get payments is going to be very similar so we're going to say use get payments query data should be let's grab this payments and
then also payments loading didn't mean to do that payments loading like that and then over here this one is actually going to be leases question mark. Z question mark. and that's going to be zero like that and we need to make sure sure this exists otherwise we make no requests so there we go I'll make sure we import use get payments query and also make sure this is a use client component a little bit of knowing to always write that and over here we are going to do property loading or leases loading or payments loading
like this we're going to return once again the loading component for any things like that and if property oh if property doesn't exist or property error we're just going to say return div error loading property something like that over here we're going to say const current lease just a variable that will help us find the current lease that we want to use so leases. find a simple find method we're going to grab the lease and we are going to say lease. property ID is equal to property. ID and for this I'm going to start copy
pasting because it is getting a little tedious and a little repetitive so I'm just going to paste this right here so we have all of this and right now we don't have a lot of these defined so I'm just going to comment this out for starters and we are going to first create the resident card so that is going to be this particular card on the left side and then we're going to create the payment method on the right and the billing history on the bottom so let's start with the residence card we're going to
scroll up we're actually going to put this above it it because that makes the most sense so I'm going to do const residence card is equal to properties with property current lease and we need to type this so we're just going to add a type over here because I didn't add a type property should come from the uh whatam call it the Prisma types so like that and we're going to do an arrow function and pass it like this so this needs to come from types Prisma types same with lease as well and in here
we're just going to return with Parn and I am just going to paste this long styling over here with div something like this with flex justify between and we are going to start with Heather and I'm going to paste this we're going to grab the map pin as well from loose side react and then save it so in our case we have our information with our image over here now we're not going to set the image for now and then we need to create the dates so I'm just going to put this over here put
slash dates like that and copy paste it and it seems like we are missing one closing div over here after three closing div we need a horizontal line like so we have so we have that and finally these are the buttons below it which is going to be after this closing div before the last closing div like this and this should be buttons and we can just say user comes from lde react same with download like this typically if I had more time I would have created the lease and put it into agreement so you
could download it over here but for now we're keeping the scope minimal for this situation next is going to be this payment method similar idea so we're going to scroll down uncomment this out and I'm going to go up create const payment method and this one does not take any properties and we're just going to return peren like so and I'm going to copy this div for the other container and then we're going to start with the headers with payment method change how you pay for your plan then we're going to add another div we're
going to say class name is equal to border rounded LG padding of six close this out and we're going to have a another div around this and inside here we're just going to say card info and pass something like this with the lucide react icons as well as the male icon and then we have all of this now this is a little messed up maybe we can fix this all right so to fix this we just have to write items Dash uh start so if you do that it's not going to do the weird you
know bubbly thing all right so that's good and then we just need the little edit button below so below the card info so this is going to be kind of hard to figure out how many closing divs so three closing divs right here below this we're going to have a button and we're going to make sure we import the loose side react and we'll have our edit and there we go normally you can do payment integration but it is again too much out of scope now we're finally going to do billing history so this is
going to be a Shad CN table we're going to go down all the way over here with the billing history we are going to pass in payments for this so let's get started with that and we're just going to write it up here we're going to do billing history pass in payments and that should be colon payments in in Array colon payment with an array like so and do an arrow function like this and then now we can import payment from Prisma types and here I'm going to return and we are going to start with
our header actually let's start with the div like this with class name you know just some basic overflow hidden Shadow MD things like that and we are going to pass in a header over here paste this and we can see we have our header again you can take this page and copy it from the repo I highly recommend because it is gets a little tedious to like write of this and then we're going to have a horizontal line right below it and then from here we're just going to have shadsy and table so I'm pasting
all of this you can take a pause what I'm doing so the table needs to come from shads and components so UI table like that as well as table header table row and table head as well as table body table will cell file text from loose side react and then check from blue side react and then arrow down to line blue side react so that essentially gives us a nice looking table over here we have an invoice the way this table works is that you have the table head for each column so invoice status billing
date amount after action and then you also have your list of payments that you got from the back end we're going to create a table Row for each create a table cell for the first one and then another table cell for the uh status which we're styling it in a very nice way billing date with the date and then the amount and then the action for a download icon and there you go that is are single residence page kind of a UI hassle a lot of work for you know just a simple page but it
is what it is all right so we finished most of the tenance pages except for the application we're going to do the same thing for managers which is pretty simple and basically the same thing so here you can see this is the my properties for a manager so basic basically I have a different user I signed in and he's a manager and he has this page where he's showing properties that that person owns from there you can see we can go to a different page for the individual property page which is another table and it
shows all the tenants for that property so pretty simple we're just going to go and see that you have the list of properties and we're going to do the same thing but first we're going to sign out and we want to sign in as a manager and once you sign in as a manager you want to go to dashboard so we can go to a properties page which does not exist we did create settings page I believe yeah we created the settings page right now it's a little bugged with the name email but for this
we want to create the properties page so we'll do just that so let's open up our pages and the first thing we need to do before we create anything is we want to create some endpoints the first endpoint we want to create is get manager property which is going to be very related to get current residences except this is going to be for manager so I'm going to copy this go down and write manager related endpoints I'm going to paste this over here this is going to be get manager properties and instead of this being
tenants this should be manager plural and this should be instead of current residences properties and everything else can remain the same as you can see we're just reusing a lot of different things so once you have all the data on the back end you can do a lot of different good things it's just the setup is quite a bit all right so once we have that we can now go to our page to managers and we are going to create a new folder and we are going to call this properties and this is make sure
it is inside your manager folder and I'm going to create a new file I'm going to call this page. TSX and to be fair this page is very identical to favorites so we can just go over here in tenants copy this page and paste it over here of course we have to do we do have to make some modifications so instead of this being favorites we're going to change this to properties go back up here and instead of grabbing the tenants and the favorites we can actually just remove all of this we can just do
data colon manager properties is loading error and we can just do use get manager property query like so and in here we want to do Au user mark. Cognito let's actually put this on the new line Cognito info question mark. user ID similar to what we have been doing all this time and we're just going to do on the next line an object of skip colon grab all of this do an exclamation paste it like that and that should be pretty good and then over here we're just going to say error loading manager properties and
then over here favored properties can be changed to my properties and then say View and manage your property listings like so below this instead of favorite properties you can just change this to manager properties is favorite we're just going to change that to be false and tenants should be managers slash properties SL propy ID like so and instead of favorite we're going to change this to manager same with over here manager and instead of you don't have any you don't have you don't manage any property like that you can save it like that get rid
of these two and that's pretty much our manager page oh we need to we do need to refresh it oh and again we're getting this issue let's actually go to residences and we want to just cop copy this paste it in the favorites as well because it seems like that doesn't seem to work and also in our favorites page as well so we'll get to a point where you know you'll be able to see it but right now I'm just I just want to create these pages and get that get these Pages done with so
from here the next thing is going to be this individual page which is going to be a table super super easy even if we can't see it it's going to be showing as well so go like that we can see what it looks like all right so and then from here I'm going to copy this page now actually before that we do need to create I believe one more endpoint there's one more endpoint we need and is the use get property leases query so we could get the lease list of leases so I'm going to
grab the get leases and uh you can place it here probably is fine we're just going to place that here I'm going to say property leases like so everything else is pretty similar except property ID we want to get a lease specific to a property and put properties slash property ID slash leases and we can basically that's it that's it for get property leases we can just go over here add use get leases property leases query comma and we can go back to our page and we can copy this properties page create a new folder
inside properties actually put it in Brackets ID like that create a new file call this page. TSX and we are going to paste it here and we're just going to change this to properties from properties to property tenants like so and what we want to do is we are going to grab ID from use params from next navigation grab property ID is equal to number ID like so and we're going to actually get rid of all of this we're going to do data colon property is loading colon property loading like this and we're going to
do use get property query from our API grab our property ID save it like that and then we're also going to get property leases query so we're going to do data colant leases comma is loading leading leases loading like so we're going to equals use get property leases query property ID and make sure that is capitalized like that and I'm going to copy this one more time this is for payments we're going to grab payments and payment loading make sure you don't make weird tablos like that and this should be use get payments query and
make sure we import that and for this is loading we are going to do property loading or leases loading or payments loading like so we don't need the error for this one we're just going to keep it like that and there's going to be a function that we're going to be using so get current month payment status I just copied it you can grab the payments the lease ID make sure for the month and the full year for a lot of this I'm not going to cover this in detail because it's kind of a headache
to deal with it because a lot of this is just UI and just some extra logic not very useful to learn too much right now and we're going to start with the back button so above this heer we're going to add this back back button and we are going to import link from next link and make sure we import the arrow left from blose side react and then we also have our header we can just say my actually we should just label this property question mark. name so the name of the property otherwise if it
doesn't exist we're just going to say property like that or maybe just my property and then we're just going to change the subtitles to manage tenants and leases for this property so we can actually get rid of all of this this time because we're not doing that we're going to do a table so I'm going to add some divs div class name with a width of full space of Y of six six like so and then inside here we're going to have another div class name of margin top of eight background of white rounded Excel
Shadow MD overflow Das hidden P of six like that and then from here we're going to deal with this Heather and this is going to be similar to what we did before you can actually copy this from uh the individual properties page but I'm just going to paste it over here so you can see tendance over here and we are going to download from loose side react go over here this is getting long so I just want to show you guys how it looks like like so make this into a template string so you guys
can actually see this better otherwise it's just too long so if I go to property SL1 you might be able to see it yeah you can see what we have so far and then below these two lines I'm going to have a HR just like that and then from there we're going to copy and paste this gigantic table and I'll just walk you through once again we have overflow Auto we're going to pass in components of table with a header and and then our row our head our body uh table cell the image from next
image we're going to pass in the name so for the first cell that's going to correspond with tenant that's going to display all this information with the image as well as the name and the email and then from there there's going to be the dates this date represents the least Peri period and then the next one is going to be the current payment status I believe so that is monthly rent F yeah monthly rent to see if it's paid and then we'll also have the phone number and then also the agreement so I'm going to
save that yeah as of right now we don't own any property so you don't see any the data but as you can see we have tenant lease period current monthy status contact and action so the contact corresponds with yeah the number so current month status so all this information comes from um like the property leases we need each lease for the lease period the payments for this payment to see if they're paid and how much it costs and basically all of these tables is to show all of that so again I'm just going to going
to make it so it's easy for you guys to see this so we have these table cells that represent each again I urge you to just copy and paste it from the repo makes your life a lot easier without having to copy and paste or like watch this and write it all out because this is kind of tedious stuff make sure I get rid of the card and there you go this should give you a brief understanding for the manager and the next thing will just be the final part of the UI finally which is
going to be the applications and also the add new property that we'll deal with so let's actually start with this add new property button so if I click here we are taken to this form page and it has a lot of inputs but this is just to create the property which is the endpoint that we created earlier and we're going to do a number of things and we're going to be using if I close this out we're going to be using the form field component that we added earlier this form field component has everything in
terms of all the different inputs and I created this because we don't want to deal with all the nuances and an annoying aspect of dealing with forms so I'm going to close this up go over here and then create a new folder within managers and we're going to call this new property and inside here I'm going to create a new file call it page. TSX and do rafc for this and we're going to say new property and like before we actually need to create an API endpoint for the create property we have the backend API
endpoint but we also need to create the front end component of that so we're going to go to our api. TS and we are going to go to the get manager related endpoints but we actually want to go up and we're just going to copy one of these mutation requests cuz this time it's a mutation meaning we're creating using a post request and changing data on the back end as opposed to just fetching data so this is a mutation request we're going to change this to create property this will be build. mutation we can change
this to property and over here this is going to be changed to form data and then inside here this query is going to be new property and the URL is going to be simply properties like this we're going to keep the method to be post and we are going to add it body and that's going to be new property like so and this should be capitalized over here with C uh camel case and over here we're just going to remove this one or we're just going to to command X the properties should be on top
the type should be managers and the ID of this is going to be result question mark. manager mark. so pretty straightforward we have our create property and then we can create a hook for this so we are going to go over here do use create property mutation something like that and we should be good to go for our API endpoint all right so let's get started so the first thing we want to do is import that create property that we just created so we're going to do use create property mutation import that then from here
I'm going to do data colon o user we're going to import use get off user query from our API endpoints something like that and then over here we're going to grab form we're going to grab it from use form in react hook form like so and we are going to import property form data this is from our schemas uh files that we added a long time ago and in here we are going to see all of these so what we can do is actually copy all of this and then paste it over here so so
we get all the initial values so what we need to do we're basically trying to write all the initial values for this and actually this seems to be incorrect we're actually doing resolver like this and I realized we need to add a Zod resolver from Hook form resolvers like this put property schema from our schema and do comma we are going to do default values colon with an object and then we can just cut this and paste it over here in the default values section now obviously the z's are wrong but we just need to
write the default values over here so I'm going to do command D for all the Z dot like this and then hold shift Command right arrow and that's going to select everything and we're just going to erase all of that then we're just going to add a comma and also empty string like this it is not correct for all of these and this last one we for photo URLs we want to just add something like that we're going to save it now this is not correct so we're just going to modify the ones that really
need default values so the price per month we can start with a th security deposit is going to be 500 application fee is going to be 100 is pets allowed it's going to be true is parking included is also going to be true for photo URLs this can just be an empty array amenities can be an empty string highlights can be an empty string beds and bath are both going to be one square feet is going to be a th000 now property type we can just exclude that for now and we'll take care of that
the address city state country and postal code can all be empty strings so this should be good so these are all the default values for the forms otherwise we're going to have some issues as you can see there's already default values for Price all of this like that and then from here we're going to create the onsubmit function first so we're going to do onsubmit basically the function that runs when we click the create property button so over here we're going to have data as a property or data as the argument and in error function
we're going to do try try catch statement like so and I'm going to do if off user mark. Cognito info question mark. user ID does not exist we are going to throw new error say no manager ID found below this I'm going to do const form data is equal to new form data like so and the reason why we use form data which is something in JavaScript is because we have images that we need to deal with anytime you have an image and you want to send it to the back end you have to use
this form data object which will make things easier so from here we're going to do object. entries Place data for each and we are going to um destructure it with key and value like so and we are going to do an arrow function and actually there should be one paren extra right there inside here I'm going to set if key is equal to photo URLs like this inside here I'm going to say const files so this is for the property photos this is representing that files is equal to Value as file object with an array
like so and files. for each and we are going to pass in file like this with an arrow function we're going to say form data. append and we're going to app pen photos with file so we're adding this to that object else if array do isarray so we're going to handle all the situations so for Value so if this one is a value we're going to do form data. append we're going to append the key as well as stringifying the value so we don't have any uh weird issues with arrays or else we're going to
do form data. append and we're going to append this key and a string of regular values so that's for like the normal situation and then finally let's just copy the form data append so I don't have to rewrite that we're going to do manager Cognito ID this is specifically for adding the Cognito ID to this object so we can use it we're going to do user ID like so and we're going to do await create property form data like so and inside our catch actually we probably don't need any of these catch try clutch block
like this because this is just already going to make an API call itself and it does seem like I did forget it closing per ends like that over there and we can save it and this should be good to go all right so from here we're going to do class name and we're going to use dashboard Das container once again because we reuse that class name quite a bit and inside here we're going to add a header if you go back up here we're going to use a header once again so we're going to import
that I'm going to do a closing tag but also add title is equal to add new property we're also going to add a subtitle like so and say create a new property listing with detailed information we're going to save that and actually we could probably see this page so if I click add new property and once again I need to add the use client it's kind of annoying that I always forget to do that and don't worry in a future video I'm going to create a nextjs course where we're going to talk about a lot
of this and a lot of advanced next J stuff but for now we're going to keep it like this so yeah as you can see here we have the add new property create a new property listing with detailed information so we have that Heather all right from here we're going to add another div and this is where we're going to actually add a form so we're going to do BG white rounded - excl padding of six so this will be like the card thing and then over here we're going to have form now don't get
confused this form should come from at components UI form not react hook form because this is a abstracted version in Shad CN that gives you extra styling on top of react hook form so we're going to add the form like that and what we need to do is do dot dot dot form we're spreading it into the form component so that is going to spread from the use form hook that we used to set the default values and we're putting it into the form component and the weird thing is that you do have to add
a form input like this or form uh jsx we're going to do on submit and this is where we do something like form. handle submit and we're passing the onsubmit function so it's not very eloquent in terms of like how this works um maybe there is a better way they could have done it but I am not sure so we're going to add a form input like that so inside there all right so from here I'm going to start copy pasting so you guys can just do part by part we're going to have basic information
and now my custom form field component works with something like the Shad CN form and then makes it super easy otherwise this page will be super long because the forms are very um complicated so we need to make sure we import custom form field and we have the name with label property name as well as description and this is going to be a text area so it's very simple to use but you have an ability for description and it's already connected to our form which is perfect so it makes our lives a lot easier and
then from here we're going to have a horizontal tag after closing div and we are going to add a section for fees so very simple we're just setting the layout for the fees oops for the fees and then we're adding custom form field for a price which is a number security deposit which is also a number and application fee which is also a number now in a realistic application you're probably going to have extra settings maybe add a dollar sign so visually they know it's in USD or maybe like a input that shows USD same
with all of these and maybe you have a min max things like that and possibly make it so you can't write decimals I don't know it's up to you on how do how you would approach it but those input things are kind of a pain maybe in the future I'll figure out how to put it into my custom form field but it is kind of a very annoying thing about front-end development getting those things is very very tricky actually surprisingly difficult for doing those kind of things so we're we're not going to deal with that
we're going to keep it the way it is so below this we're going to have another horizontal line similar to before and from here we are going to deal with property details so below this I'm going to add a section and it's quite a bit for this one and we do have property type enum which seems to be not defined so we are going to import it manually I'm not exactly sure why it's not actually triggering in error or a linting issue here but there you go once you put that we'll have this property details
going to close this out we have the property details the title over here and then we're going to have beds baths square feet and then we're going to have something called switch which right now if you tell it's a little messed up so we actually need to fix our switch component in chaden and also over here we have a property type so this is going to be a a drop- down select button so to fix this we actually need to go uh close all of this out we're going to go to components UI and go
all the way down to switch and we need to make a few modifications So Below this on the next line because we don't want to modify what's already there we're going to do data- state is equal to checked we're going to do colon BG primary -700 comma and also do copy this over paste it below here and we're going to do state is equal to unchecked BG gray 400 like so and then for the thumb we want to change the color too as well so we're going to go down here to BG gray 100 and
it seems like I forgot a comma up there let's save it and see what we have and as you can see when you click on it it becomes darker and when you don't click on it it is much more visible so that is good all right and then from here we're going to copy this HR for below the closing two divs over here we are going to grab or paste amenities and highlights for our next section and again I'm not exactly sure why it's not linting right now but it is very very strange so amenity
enum and also highlight enum we need to import them from at libc constants so over here we have our title for our amenities these are going to be a type select and the options we are using amenity enum highlight enum to show the value and the label so anytime you click you can see all the options that we have technically these are supposed to be in array for all of these but we're going to keep it simple and keep it to be a singular string so it doesn't make things too complicated so there's that and
then over here we have another H check and as you can see this custom form field is very handy makes our lives easier when dealing with forms otherwise we have to deal with the nightmare of validation and a lot of custom code writing and over here we have a with uh photos custom form field this is a type of file in this case custom form field is going to use the file Pond library that we did right here so that allows us to add some kind of random images for our properties photos so if I
just do something like that we can actually see a little preview of what we uploaded so that is pretty nice and you don't we don't want to deal with that that might be a video from for another day in terms of handling big forms otherwise we're going to continue create another horizontal line and right here is just going to be the last bits of additional information so I'm going to paste that one as well so here we have additional information as our title with address uh city state postal code and our country now typically instead
of this country being like a input string you would probably do a drop down of all the cities states or zip code make it easier um but for now we're going to keep it simple and the final thing is just going to be the button that we add this is going to come from Shad CN and it's going to be a type of submit so instead of creating a onclick Handler we just do type of submit and we can just create our little button at the very bottom to send and create a new property to
the back end all right and that's our create new property so let's actually create a new property test this to see if it works we're going to do one thing before we do that we're going to go to our back end go to property controller we're going to go to create property all the way down over here and for now we're just going to comment the photo URLs out because right now we do not have the S3 bucket we do not have that set up so we're just going to keep it like this so property
name we can say test property give us some random description we're going to keep all of these to be default maybe remove the pets keep refrigerator satellite TV we could just add a random image now this image won't be uploaded so it doesn't really matter but as it's I believe I have it required so you can't do anything so for this we want to do Santa Monica Pier because you might get some issues if you don't do this correctly we're just going to do this for test purposes and we are going to say United States
and if I hit create property let's actually before we do that open this up in our Network tab so we can do create property oh and then we get a crash because this photo URLs is commented out so we're going to keep it like this we're going to comment the photo URLs out from there too so we're going to do npm runev restart our server make sure it's running close this and we're going to hit create property once again as you can see it says 2011 created everything seems to have worked which is perfect and
let's actually go to our properties page and there you go we can see our test property we can even click it but we don't have any tenants for this property so regardless this is a good achievement for what we want all right so before we get onto the last part which is the applications which is the final stretch of building the application we are going to go and open this up I'm going to close both the client and the server we're going to do another I'm going to go to The Parent Directory I'm going to
do get uh add dot git commit DM and we are going to call this uh property dashboard complete so all the property Pages property Pages property dashboard Pages complete we're going to make sure we commit that get push origin Master if you guys want to check that out double check if you guys are doing it correctly so I'm going to go back to client and then run mpm run Dev and run our server once again as well all right so from here it's going to be the applications page so we're going to start with the
managers so pretty straightforward but it's going to show whether the application has been approved um if it's been denied or if it's pending we're going to have a couple tabs mostly a UI thing but the application is a little bit tricky um not too bad though so I'm going to go over here to the managers uh folder we're going to create a new folder we're going to call this applications and inside applications we're going to create a new file called page. TSX and I'm going to do rafc e and create applications something like that all
right so as before we need to make some API request so I'm going to go down to State and go to api. TS and we're going to create a new section we're going to call this application related endpoints I know we're at the we're at the final stretch so bear with me so in this we're just going to copy the get leases paste it over here and we are going to do get applications like this so build. query we're going to actually change this to application instead import that from at types property Prisma and this
value right here instead of it being a number it needs to be an object with user ID question mark colon string semicolon user type question Mark colon string and that should be the typing for this now for the query it's going to be a little bit uh different we want to modify our query so we're just going to do params with an arrow function like this and we're going to do const query params we're going to do new URL search params which will make make it easy to create our URL search prams we're going to
do if pam. user ID exists we are going to do query ps. append user ID comma pam. user ID to string like so we're appending the query pams for user ID if it exists and if pam. usertype is equal exist because sometimes these might not exist that's why we're doing something like this we're going to do c query pams the depend we're going to add user type we're going to also add prams do usertype as well so we're just adding query prams optionally if they exist and we can just do return uh template string so
like just like we did before we just return the template string we can say applications question mark dollar sign query prams do2 string and invoke that so we're going to have a query like that and in this case we're going to provid tags applications and so if we take that we can just go back up and add applications like this all right that's good but we also need um whether the user can approve or deny the applications so that is going to be dependent on a mutation call so let's go up where we see create
property we're going to change this or copy this I mean paste it over here and we are going to say update application status like so this will be a build. mutation and we're going to have a few things over here we're going to say app application and Lease optionally so the lease can be added on top of the typing that you might get back from the back end and also we are going to add an object to send to the backend ID of number with status colon string inside the query we're going to pass in
ID comma status for the URL we're going to do application slash ID slash status like so the method is going to be a put and the body we are going to send the status as part of that body and for invalidate tags this we can just get rid of a lot of these fancy things and inside here is just going to be an array we're going to do applications and leases all right simple enough and then with that we can add these to the queries use get applications query and use update application status mutation we
can save that and then we can go back to page. TSS all right over here we're going to grab data colon off user and do use get off user quer import that and also we're going to grab active tab set active tab like so grab from use State and we're passing in all as the initial so that's going to represent which state we are on and then from here we are going to grab applications as well as is loading is error and we are going to grab it from use get applications query which is what
we created and passing it in user ID so op user Mark Cognito info mark. user ID and the user type in this case is going to be manager because we are in the manager Pages we can just hardcode that and we're also going to add an object of skip like so we're going to skip and I'm going to copy this right here so I don't to retype that and make sure you have have an exclamation and we can just save that that will Auto format and then below this we're going to grab the other one
update application status and we are going to use use update application status mutation like that we're going to invoke that and then over here we're going to do handle status change and we are going to do async ID colon number comma status colon string so basically we're just going to invoke a wait update application status pretty simple and we are going to pass in the ID and Status like we did mentioned before and below this we're going to do if is loading we're going to return the loading component from our components that we created very
handy to make this really quick and easy if is error we're going to do exclamation applications like so we are going to return div error fetching applications easy enough and then we are also going to filter our applications depending on the active tag so we're going to grab applications and we needed to do this on under the if conditions otherwise it won't exist we're going to say applications question mark. filter we're going to grab the application with an arrow function like this we're going to set active tab is equal to all we are going to
return true like this otherwise we're going to return application. status. two lowercase is equal to the active tab so we're just making the check right there and now again if we go back to New property we can actually go back up here and we're just going to copy this first part and then paste it over here press the wrong button and make sure you have header like this save it this is going to have applications and we are going to do subtitle View and manage applications for your properties something like that all right so from
here it's all about adding these tabs and then also creating this application card so let's do just that so I'm going to start importing a few things or copying so I'm going to do right below our header I'm going to add these tabs I'm going to going to make sure we close the tabs as well so we have tabs with the value of active Tab and changed via set active tab we're also going to import tabs from our components and the tabs list from our act components as well as the trigger like so so we'll
have our tabs on our pages so if I go back to my application and again we need to do use client like so you can see we have our tabs but with no tab content now realize in this case we don't have any applications for the specific user and we'll handle that near the end and I know you can't visualize anything while I create the rest of this stuff um don't worry I'll show you at the very end on how all of this looks just make sure you copy all of it correctly so over here
we are going to do all comma like this or comma pending comma approved the comma and denied and we're going to map this to each tab content via tab with an arrow function uh PRS and we are going to pass in tabs content from at components UI tab we're going to close this so we have that but we also need to pass in key which is going to be the tab value is also going to be the tab class name is going to be margin top five with full like so and inside here we're going
to pass in the filtered applications and right now we're going to this user does not have any applications attached to them so we're not going to see anything so we're just going to do filter pass in application we're going to have an arrow function and we are going to do tab is if that's equal to all or application. status to lowercase is equal to tab we're going to map this out and we are going to say map application and then from here we're going to be passing in application card we're just going to keep it
like this for now right now there is nothing but we need to create an application card which is going to be used in the other component as well in the tenants version because there's two application pages one for manager one for tenant and they're going to be slightly different but we are going to reuse the main gist of the component and we're going to modify a few things so I'm going to create a new file inside components and we are going to call this application card. TSX and inside here I'm going to do RFC with
application card all right so in here I'm going to put curly braces application comma user type comma children so we are going to pass in children component for this and we're going to do application card props like so now inside here we're going to have a backup uh image so if we go back to just regular card. TSX over here we can just copy that code that we just had for the image source make sure we import that but this one is going to be application. property photo URLs so this is just going to have
a backup image just in case and also we're going to have a status color I'm just going to copy and paste this which is from if application status is equal to approve we're going to have BG green 500 otherwise if it's denied we're going to have red otherwise if it's neither of those is going to be yellow meaning it's in pending State and over here we're going to do const uh contact person and that's going to equal to user type if that's equal to manager we are going to say application. tenant colon application. manager like
so all right and then from here we're going to do our normal thing and modify this so I'm going to say class name is equal to border rounded Excel overflow Das hidden Shadow smbg white and margin bottom of four below this I'm going to have another div and this one's going to be kind along we're going to have Flex Flex column for large we're going to do Flex row let's actually close this up and then items Das start with LG yeah we need more space more space like that so LG colon items Das Center justify
Das between px-6 MD colon PX4 P1 y-6 Gap D6 and LG Gap D4 a lot of classes because it's very long and a lot of responsive design all right so from here we're going to have the property info section so start off we have an image that's going to represent this image right here take a look on bigger screens this is the property info section that should represent that and it's also responsive as you can tell and then with the map pin we need to import that as well we have our image we have the
name we have location or basically address and El the price per month and the next thing is after three closing divs right here one two three we're going to add a device and this is only visible on desktop or larger screens so that represents this one right here this long line and the next part is going to be the status section with the dates so I'm going to copy and paste that so that should represent this guy if you have that correctly you're going to see that we're also going to just copy this once again
and paste it below which is two closing divs below we're going to save it like that and then finally we're going to have the contact person section below the divider we're going to have it like this we need to make sure we Import phone call from loose side react as well as the mail from loose side react like this we'll have the name phone number email with that particular section and finally there's one two three four five closing divs we're going to have a horizontal line and also we are going to put children like so
so that means in this page the tenant application is slightly different so that means we can actually put whatever components we want below so this last part is going to be custom for manager and also tenant so it's going to be different for both of them so in this case we need to write this inside the manager uh application page whereas it's going to be different for tenant so let's go back to applications and now with these fragments we can actually change this so we can change this to be application card make sure we import
the correct application card close this out and then also pass in the correct PR so we can do key is equal to application. we can also pass in the application into the application card if I can spell that correctly application we're going to do user type is equal to manager and inside here like I mentioned we can pass in children type elements so first off I'm going to do div class name Flex justify Das between gap of five withth of full padding bottom of four px- 4 and we are going to close this and below
this we're going to have the colored section section status I'm going to paste this over here and as you can see there's a lot of conditions depending on whether it's approved or denied you're going to have different colors and it's going to show different things application has been denied instead versus approved and there's also one for pending which is going to be yellow so make sure you import the correct things such as this circle check big and basically we are having different styles and different text depending on their status that's why it's kind of just
a big section and below this we're going to have two closing divs and we're going to paste this last part and this is just going to represent the the right buttons those are the two buttons nothing too fancy I'm just going to show you uh you guys can write it yourself import next SL link so this will take us to the individual property Details page and then also Hospital which comes from lde react the download icons also from lde react and we are going to have if the application status is pending which we don't see
here we're going to have two different buttons which will say approve or deny for that specific user so it's very dependent on the pending status if it's denied this should say contact user otherwise um we have download agreement so a lot of different conditions depending on the status of the application so as you can see that was quite nice to write this application page and just real quick I'll just show you let's actually move this so you guys can see all of this um and what I'm going to do because it might be hard to
see on your screen so I'm just going to create these into template strings and by the way these two these two class names right here are pretty much identical so over here I'm going to change this so you can see PX4 we're going to put it on a new line like this once we close it you can see that we have both of these they're exactly the same and this one right here is pretty similar except it's slightly different which is kind of annoying but yeah you guys can see all of this I'm just going
to show it to you slow like this so you can pause the screen if you need to write it otherwise you can go through the repo all right and then this is the applications page for the um tenant pretty much identical except this uh bottom line is going to be different it's just going to show slightly different thing and this one is going to be easier so let's actually do that real quick so if I go above here we're just going to close this out close new property and I'm going to probably comment or copy
all of this from applications and we can go to tenants create a new folder call this applications and we can add a new file we're going to call this page. TSX and I'm going to paste it over here and we can make modifications from here and this will be pretty simple I think there's not much to change so over here we don't need a skip this time we're just going to remove this we don't need active tab and this time the user is going to be tenant like so we don't need update application status M
mutation in this case get rid of handle status change and get rid of filter application and then we can remove these from the Imports and then over here in our subtitle we can just do track and track and manage your property r rental applications and over here with all of our tabs we can just get rid of all of this right here we can actually change this to be a div with a class name of width Das full and close this out we're going to cut this out over here go all the way down see
where tabs content is we can just put a closing div over here and we do need to close it and so you just want to do two closing uh PRS and the closing curly braces let's save it so it formats and for this uh applications we can actually just get rid of all of this above here before our map I'm going to do applications question mark. map we're going to pass in our application card like our usual and I actually enabled this user type of renter should be tenant but renter is fine so there's a
few things we can actually uh copy we're just going to cut this button for download agreement we're going to remove the approved we don't need that so that is one thing we are going to be using we're going to paste it over here oh by the way I seems like I have a typo justify Dash between let's go back into our managers we're going to fix that as well justify so we don't get any weird issues so we have justify between we also have this button for download agreement and you know what let's actually just
remove everything else because it's better if we just start from scratch we're going to have make sure you have a closing div like this so we have our button for download agreement but we need to write all the parts for application status so I'm just going to paste this these are our status application status approved we're going to add this circle check big property is being rented by you until a certain date if it's pending we're going to add a clock let's make sure that gets added from lde react and X Circle as well meaning
your application has been denied so we have that we have the download agreement and that should be good for our application pages and then from here we're just going to we we definitely want to remove all the Imports that we are not using so let's get rid of all of those and then we can save it all right and then the final stretch for our applications is we're going to go to the front non dashboard page so if I go over here on the finalized application if you click on one of these right here when
you hit submit application you should be able to see this little form to submit an application for a specific property so to do that we're going to close all of these and I'm going to go to non dashboard back to the front page we're going to go to ID and go to page. TSX and over here right below our uh contact widget we are going to add off user if they are signed in basically we are going to add an application model that we will create sure we have a self closing tag and what we
are going to pass in is going to be is open to make sure the model is open as you can see we set this up a while back and then also on close we are going to have an arrow function we're going to do set is mod will open set that to be false and then property ID is equal to property ID like this for our application model so our application model we're going to create a new file for that called application model. TSX and do rafc and create it like that and then make sure
we import it as well so that should be pretty simple and inside here we're going to add all the properties that we just added so is open onclose property ID with the colon application modal props now over here we're going to do const create application and we're going to do use create application application mutation which we have not created so let's actually do that real quick I promise you this is pretty simple so let's actually go up go to the create property one we're going to go down to application related endpoints and at the very
end we're going to paste the create property but we're going to change this to create application the build D mutation should be instead of property it should be application like this and then this is going to be partial so the user can submit like a partial version of the application make sure you have a closing one a closing angle bracket like that and then inside here instead of new property we're just going to put body like that for URL this is going to be applications method will remain post and the invalidate tags is going to
be a lot simpler we're just going to have uh angled brackets or not angled brackets square brackets and we're going to put applications like this and then from here we can then import this use create application mutation actually after we add it right here use create application mutation then we can import it like so and then I can do data colon o user and we can do use get o user query from our apis and then we can actually just go back to new property and we want to just scroll up here we're just going
to copy this form just so we don't have to write that out I'm going to paste it and I'm going to change a few things obviously I'm going to change application form data make sure that gets imported instead of property schema we're going to do application schema the default values we're just going to remove everything except name put email with string phone number with string message with Goen string like this and also we need to do onsubmit so we're going to do onsubmit function we're going to do async with data colon application form data with
an arrow function we're going to say if o user o user. user Ro does not equal to tenant this is just a if check just in case making sure that they are a user we're going to just say console do error you must be logged in as a tenant to submit in application just in case if they're like a manager or someone else you don't want that so in this case we're just going to return make sure they don't submit an application otherwise we can do a wait create application and we're going to drag out
all the data application date call in new date to ISO string we're going to do status of pending property ID colon property ID tenant Cognito ID colon o user. Cognito info. user ID so just a lot of information passing and we also want to make sure we invoke on close so the uh modal gets closed and for this section I'm just going to paste this because I am running a little bit short on time so I'm going to paste this it's very simple we are using dialogue we're passing that in from Shaden component which is
just a modal same over here with the content with the Heather and then the title and then the form from our Shad CN not react hook form like we did before and it seems like oh this should be dot dot dot form like that and in the custom form field should be imported as well and that should be good aside from the button import that that should allow us to finally submit an application and of course we do forget we need to import use form from react hook form as well as the Zod resolver from
Hook form resolve and make sure you spelled message instead of with an N should an m and that should be good so let's go to our own application I'm going to sign out and what I want to do from here is I'm want to test the application if you go down we should be able to see the test property that we created from a manager so there's nine places this one should have been added and over here I'm logged into my tenant account make sure you have two accounts one is for manager one is for
tenant and in this case I'm doing ten uh tenant so I'm going to hit submit application we can just do test uh just some dummy email random phone number number blah blah blah and submit application now typically you would see uh toast notification I'll come back to that later and then from here what we want to do is actually log back into our manager account that has this property so let's do that if you go back to your manager account we see test property we're going to click on it and right now we haven't seen
anything but for application you should be able to see that we do have this application submitted perfect and you should be able to see it's in pending approv denied is going to be empty but over here let's click approve oh and it seems like we are getting this error because I think the method right here should be a a put I put a two T's right here which is a problem so that seems to be the main issue let's let me double check everything okay so that seemed to be the main issue it says application
has been approved and it gets updated so that is that is quite awesome that it worked everything is working as expected and and you'll probably see the changes reflected on the tenant side for this application so yeah from here there's going to be a few things that we're going to change but let's we'll get to that and with that that's pretty much the entire application but there's a few things I want to change if you go to Landing we can see the homepage but we also want to be able to see the homepage over here
at slash but we just have home at the current moment so I'm not exactly sure the best process of handling this maybe there's a better way but what I'm going to do is basically go over here and we can just copy most of what we see here we're just going to copy this in the layout for non dashboard and then we're going to go into our page and we are just going to paste it now we can just import nav and Navar height actually we can just reduce we don't need it for this situation and
also we can just pass in landing component so if we do that slash like this and I'm going to save it and you refresh it you can see that we have our entire page which is perfectly good and one thing I did forget for the landing page is this search bar so let's get to that so we go to landing and then we go to Hero section I'm going to close all of these out and I'm going to close my left browser what we want is a function for this search which we kind of left
earlier I did forget to mention about this so we're going to go up here at the hero section and we're going to do a number of things we're going to do const dispatch is equal to use dispatch import it from react Redux we're going to grab search quiry and set search query and we are going to import use State and put an empty string over here for the state of the search and we're also going to grab router from use router next navigation make sure I invoke that and over here I'm going to create a
function called handle location search with an async function Arrow function like that and what I'm to do is a try catch block basically and we are going to do const trimmed query so we're going to take the search query we're going to trim it so that there's no white space at the ends and if it's not trimmed query meaning it doesn't exist we're just going to have a a null check we're going to do return semicolon and then I'm going to say const response and I'm going to do await Fetch and in this case we're
just going to do a template string we're just going to take https colon api. mapbox.com [Music] geocoding sv5 SL mapbox doplaces SL dollar sign encode URI component and we are going to add the trimmed query over here and I'm going to do Json Mark accessor token is equal to a dollar sign process. env. nextt public mapbox uncore accessor token and this is to call our API mapbx and allows us to grab the location so I'm going to do and fuzzy match is equal to true the documentation is all there we're going to do semicolon we're
going to do const data is equal to await responsejson invoke that and we're going to say if data. features and data. features. length is greater than zero we are going to do const longitude and lat like this we're going to grab it from data. features z. Center and then we are also going to dispatch set filters so set filters is our uh what was it Redux Redux function that we can set the location colon trimmed query comma coordinates colon lat comma longitude like this and this is very handy to use Redux for something like this
because it's available and accessible from everywhere that's why I do recommend using Global State because there's situations like this where if you had the pass to query prams and you have to do Redux contexts it's an incredible pain so any anything that has Global state is very useful for things like this and then we're also going to take the location colon trimmed query comma lat is equal to lat two string invoke that longitude is equal to longitude to string and then we're going to do semi cly braces and then I'm going to do router. push
template sing SL search question mark dollar sign curly braces params to string like this and that should be enough and we're going to do a catch block we're going to say error close that and we're just going to do console do error error searching location colon comma error like so and then we're going to remove a closing curly braces and we are missing a curly closing braces over here for the if so make sure those are correct and we still need to go down over here to our input we are going to change the value
to be search query like this and then on change is going to be e remove this to be set search query and we are going to pass in E target. value and over here on the onclick button we're going to change this to handle location search so we have search by City neighborhood or address and we're going to be able to search the query once we make the API call so that should be pretty good now and finally if you take the final application we can be able to see that over here we actually have
these buttons where it says added to favorites or removed from favorites and we're going to use something called Sunner from Shad Cen which is actually very nice if you go over here this is the one you want there is also a toast one but sunar is the one that you know they have a stack and I think that's a lot better it looks very nice and we've already installed it so all we have to do is go back here and we have to initialize it inside our layout component so in our layout component I'm going
to go up here I'm going to do import toaster from Center so this is going to be from at component Sunner and over here right under providers we can just pass in toaster like this with a close button and with this we can just add a notification anywhere in the application however we do have to figure out when this should be called and of course these are going to be called in API calls as I mentioned however you don't want for every single API call so when you go to this page and we fetch success
uh uh what was it a successful properties list of um homes that we get from the back end we don't want the notification for something like that but when we click some buttons like this when you're doing interaction that is something you want which is generally mutation calls for mutation calls where you do a update put you know or delete things like that you want feedback even if it's successful whereas for fetch calls you only want to provide a toast notification if it fails all right so to do that in this case before my other
application I did it I did a general one that will make it a lot easier otherwise we can do something like this where we can add notifications for each manually and I'll show you how to do it this way this time there's no wrong or right way to do it one has less work but sometimes you can't customize it as well if you see in my learning management application I had this um I changed the base query in our API call I changed this so it it accommodates it but it's a little inflexible sometimes so
there's an alternative way to do it in Redux toolkit which if you go over here we can start with get properties so this is a fetch call so we actually only want uh error when it or we don't we only want a success or toast notification when it shows when it gets in error basically so we right below our provides tags we're going to do async on query started and we are going to pass in an underscore like this because we're not going to use that first argument and that's basically the standard and we're going
to say query fulfilled we're going to do curly braces and we are going to do a wait and I have this function called with toast and I'll explain what's happening in there which is a utility function function I created to make this a little cleaner and inside here I'm going to give it an error and say failed to fetch properties and that will give an error when we have an error for get properties if it cannot fetch it then it'll give us an error so what's happening here is on query started basically once the API
call finishes and once we get a response via query filled we can go to with toast which will show us that in our messages we're going to either have a success or error so if it's a mutation function in this case we pass in success so success colon whatever text it is otherwise if it's an error we are going to invoke our toast component for the error so only mutation ones are going to have this part of it otherwise the error is going to have this one so that is all you need to set up
the fetch functions and we're going to go one by one and we're going to do we're going to copy this to get property and so most of these are going to be pretty simple we're just going to say load property details and most of the time it's just going to be the same for everything else so get tenant we're going to go down we're just going to say failed to load tenant profile same with get current residences paste that we're going to have failed to fetch current residences Now update is a mutation call so in
this case we're going to have an error and we're just going to say fail to update settings but when you change the settings you want a success toast message so we can say settings updated successful something like that and that will provide message or toast for both of those situations all right and then I'm going to copy this one because it's more descriptive and we're going to do the same thing for add favorite property and this should be added to favorites like so and we're going to say failed to add to favorites same thing over
here for remove Favorite property we're just going to say removed from favorites and then this one's going to be failed to remove from favorites get manager properties as you can see this is kind of tedious but sometimes um this is probably the easiest way to handle something like this so fail to load manager profile go over here to update manager settings fail to update settings and settings update that we can just keep that go over here for create property we can just say property created successfully and fail to create property and this is one of
those situations where you know AI would be helpful but since I don't plan to use AI in my videos because it makes it like not very helpful for me to teach you so we're not going to do that for get leases we don't need success we're just going to say failed to fetch leases same thing over here we're going to remove the success and fail to get fail to fetch property leases a lot of times if you just have like a simple error message it's generally enough same with payments fail to fetch payment info same
with get applications we're just going to remove the success fail to fetch applications go over here update application status so this one has uh status and we can say application status updated successfully fail to update application settings and then finally with create application we're going to paste that we're just going to do us application application created successfully and fail to create applications and with that that should cover all the last cleanup I wanted to do for our application we now have notifications we can test this real quick we can go to search page and we
can try removing it and add it we should have that so everything works quite nice and it looks better it actually looks I personally like this design better than the one I originally had for the map so yeah that covers everything on our UI side now we can do one last thing which is upload this final commit onto our repo and now we can start doing our fun stuff which is AWS deployment all right so let's actually get to that that we're just going to go open up our terminal close out of this I'm going
to do CD dot dot close out of this one I'm going to do get add dot so add everything get commit dasm and we're going to say final or no cleanup app and then get push origin master and we should be good to go for our git repo actually there's one last thing I want to do and this is for specifically deployment so we're going to go um to I'm going to close client and in our servers go to our index.ts we want to go into our port and because we get some issues with the
unv variables we want to add actually a number around the port and also we're going to add Z 0.0.0.0 like this add a comma over here and it should have no problems once we deploy our application and then also in our server directory I'm going to create a new file I'm going to call this ecosystem. config.js now this is exactly for uh pm2 which is going to be some node library that will help for node.js production applications running on ec2 so this is just something I have been doing but this will allow us to make
things a little easier so I'm going to do module. exort curly braces apps uh square bracket curly braces Name colon project-management comma script colon npm comma args colon run Dev comma EnV colon nodecore EnV colon development so this will help us start our applications once we are on there make it make our lives a little bit easier all right from here there's actually a couple errors that you'll run into before we deploy our application we actually need to run npm run build on our client for nextjs application before we deploy it otherwise we're going to
have issues on the actual deployment so the first thing that's going to prevent you from doing anything if you try running npm run build it's going to fail and that's because we're going to have es lint telling us that certain things are not linted correctly and for now in a real application I would probably fix this myself but dealing with a lot of these like explicit NES they're going to be such a pain in the butt that we don't want to deal with any of those so we're just going to do typescript dases lint SL
no explicit Das any grab and say off like that and we're just going to copy this six times we're going to have a lot of these rules and we're just going to change a lot of these we're just going to say no unused DVS no empty D object-type no unnecessary Das type- constraint no wrapper D ob- types no unsafe function Dash type like this I'm going to remove this one and that should be good now if you if you try to run npm run build you'll probably run into some issues still and so we get
something like this maybe you get something different sometimes it's very buggy so what we want to do is grab over here we're going to delete node modules and we're also going to delete package lock and we're going to try reinstalling it see if that's an issue all right and then we're can try running npm run build once again and there you go if you see something like this all of this over here would not found everything should be pretty good and we should have no issues I do want to check running our server before we
do anything because we did make changes we want to be able to still run it locally yeah that seems to work so I'm just going to cancel out and so yeah and the last thing I just want to do is again go to our Parent Directory I'm going to do git add dogit commit DM deployment update and you get push origin master all right so here is AWS so the next few Clips are going to be from a previous video so if you already watched the intro budget and deleting section of AWS I had in
my previous videos you can skip those parts and go straight to the AWS architecture which is going to be completely new otherwise you can start watching it from the beginning to see everything about AWS if you're new to it and now for the most exciting part of this application which is where we deploy our application using AWS now there are platforms like for sale for nextjs or other services like like post postr SQL which might be simpler I believe AWS is such a valuable skill to learn I really wanted to include it because it stands
out on resumés and impresses interviewers because there's such complexity and such a wide range of services now I know AWS is pretty daunting with its extensive terminology and buzzwords but mastering it is really beneficial especially in this competitive job market and that it shows you can handle complex technical tasks Beyond basic crud applications if you could just click and deploy that is not a very useful skill also this entire tutorial where we deploy our applications it's going to be entirely free and I'm going to make sure that you understand everything about billing the free tier
and budgets and we're going to go through all of that in depth so let's get started so if we go to AWS we have a sign up for AWS now I'm not going to go through this exact process but it's pretty simple you just have to follow the instruction so you would go through this process add your email there's going to ask for email confirmation it's going to ask for your billing info and then you can choose free tier just realize we're going to use a free tier account so I want you to put an
alert for after 12 months to check when your free tier usage is up just in case so you don't get charged on after that 12 month now once you sign in you'll probably see something like this particular page I just want to let you know that there are three ways to interact with AWS and that includes the console which is what you see here which is the graphical UI for accessing AWS Services there's also CLI for those who prefer using the terminal to type commands we're not going to be using any of those and then
there's the STK if you want to programmatically manage AWS services and have automatic you know automations that you want to interact with these Services now before we get started I want to talk about billing cost and free tier as well now this whole video is going to be about free so everything we do is going to be free for this entire project but I want to make some caveats just in case so that you don't get charged because you can still get charged accidentally if you don't do the right things so I just want you
to be aware of this this is a huge part of AWS and a huge thing that you need to know first off there are some services that have free trials there's other ones that are 12 months free so you have a free tier account a lot of services have free tier options and then there's some options like always free that includes like Dynamo DB other things like that so you have to make sure what you're using is dependent on what you're looking for over here because there's a lot of options and under here there's a
lot of options over here so you can see all the link in the description all of these and the services that are going to charge you so you don't have to worry for each section I'm going to tell you what is free and what is not so we're going to get to that so let's go back to our console now we're going to go over here you can look up search you can look up services over here but it's better to just use the search and we're just going to go to billing and what we
want to look at is billing and cost management and I'm going to briefly go through this so building and cost management this is a very complicated page but there's only a few things that you really have to pay attention to the homepage is where you get a brief summary and overview I look at this this gives you a little cost breakdown it's pretty simple and then over here you can see the bills this obviously gives you the charges and importantly you can see what services will charge you right now I have everything to be zero
if you followed my last tutorial I have reduced every cost to be zero so nothing is charging and a few other things is the cost Explorer if you want to use this this is more for advanced use cases you probably don't have to go through it I've been charged $19 because I was using a accidental VPC ipv4 which I removed and over here pricing calculator is another option you can use which will help you create an estimate but again this is probably for this is for very Advanced use cases and then there's also free tier
over here this will be useful for your free tier account it shows you what you're actually using for the services that you are getting for free in your free tier account so the 12 month limit this is what you get so make sure you take a look at this this is an important page and then finally budgets is another useful one so what we can do is create a budget what I have is a free tier budget and it tells you when you are going to go over a limit so if you create a budget
you can use a template and we can set zero spend budget and I'm just going to create that budget let's say okay and you just want to write your email so that you get a notification if it goes over that bound of the cost right now zero spend budget meaning anytime it exceeds 1 cent it's going to alert you once you create that budget you're going to see that the budget is set to $1 you can chain it into 1 cent but you might get warned a little too early you probably want to set it
to maybe 10 cents or something like that if you want to do that you can go over here you can hit edit and what I want to do is just go into enter your budget amount I'm going to say 10 cent like that so over here you're going to hit next next none of this really matters you can configure it you can look at all the options but it's pretty self-explanatory from there so if you hit 10 cents my forecast amount says 5 cents because this is incorrect you just have to be noting that this
value might not be right so I have my zero spend budget at 10 cents which is warning me then and it's going to give me alerts so there you go that is mostly the budget is very important to understand see how to make it so we don't get charged for anything so one last caveat right now I'm recording this in 2024 but maybe you watch this in the future you have to watch out and be careful about aws's pricing because they do change quite frequently whether it's the products or services so you always want to
make sure you understand that and the best way to figure that out is go to this particular fre tier page go down and go under here you can search for free tier products and if there's a service that you want to use and you want to check if it's free you can go to S3 and you can see that it has 12 months free it has 5 gigabytes that you can use for free for 12 months so you always want to make sure and double check over here this is a very good overview very good
summary this is probably the most helpful page when it comes to pricing that I've discovered on AWS now real quick this part is optional if you watch my previous video you might have extra services that you had before so what you would do is you want to be able to delete all the services that you made prior and just in case you have issues with deleting Services you might not know what services you're currently running because you might have created a few things that you don't know and the way you can check is we can
do two things we can go to the bills page to see what's running and you can see what's being charged of all of these you can see everything that we have 12 Total Access services so you can find what you already have in that specific region figure out what is being running currently so this is everything I have currently being shown but another way is you can go to the VPC and inside here you can see everything that all the services that we basically have so you might have some things that you probably don't know
what it was all about so you can go through over here and you can basically try and delete them just realize that deleting them can be kind of a pain it is a little bit difficult and they probably purposely do it but basically if you want to delete something like this it is hard because there are dependencies upon which services so you're just going to have to go through the manual TDS process to see which one can be deleted first for example if you try to delete a VPC it might prevent you from deleting it
because you have all these subnets associated with that so there's a lot of dependencies on what you can delete so you're just going have to go through figure out which ones are going to be deleted first so just letting you know make sure you delete the services if you already have them just in case you have it from a previous project all right so in this application the architecture isn't too different I wanted to keep it simple but here we have the client computer and our AWS architecture in the AWS Cloud so AWS Cloud represents
the internals of AWS we're going to be using using AWS amplify for our front end and then API Gateway for our API entry point and then we're also going to have a ec2 backend which is going to be on the ec2 server which will represent our node server and then RDS is where we're going to have our database we're also going to have an S3 as well as Cognito for authentication we've already created that so we don't have to worry about those but we can worry about all of these other setups and I'll show you
everything you'll need to know for the networking and making sure you don't run into the common issues you have when dealing with AWS all right the first thing we're going to be handling is going to be this VPC over here this VPC is going to be the main thing we are dealing with with networking anytime you're using something like ec2 and RDS generally you're going to have to use networking if you use Dynamo DB or Lambda that's a different story but in this case we have to know a little bit about networking and I'll go
through walk through every step of the process so you guys can understand what is happening so let's go to our AWS console home we're going to go to VPC in our isolated Cloud resources and inside here make sure you're in the region that you want to handle because you got to remember which region you're going to use in my case I'm using Us East 2 so use whatever VPC closest to you and I'm going to see that I already have a VPC but I want to create another VPC you might have a VPC by default
when you create your account so make wary of that but instead I'm going to create a VPC all right so now from here I can say VPC and more which will create a lot of subnets and Route tables and connections for us but we're going to do VPC only just so I can show you everything that's happening here I'm going to call this rore VPC for Real Estate VPC I like prefixing it with the name or abbreviated name of our application makes our lives easier and then from here this cider block we're going to keep
it ipv4 CER manual input but ipv4 is a crucial part of understanding IP addresses is and this identifies where your server is located basically AWS has their set of IP addresses that they use basically they're like domain names domain names are shortcuts for the IP addresses they're human readable but IP addresses are the actual locations of where the server is located and inside AWS even when it's private by default they won't be accessible to the outer public those IP addresses need to determine where your websites are so it looks something like 10.0.0.0 sl24 so when
you set these CER blocks these are ranges in which your servers can be located so if I say something like 10.0.0.0 sl24 that means in this case these first three are locked now I'm just going to show you this is a very simple understanding of IP addresses but it makes a lot of sense so that means when you do sl24 it means there's 24 bits that means it is capable of handling locking these three and only the last number right here can vary from 0 to 255 as you can see any of those numbers can
be assigned to be those IP addresses and then when you do 16 very similar so 16 bits that means two of them are locked so these two first values are not changeable but the other two goes from 0 to 255 and same thing with 0. sl8 so when you have those all three numbers in from below 10 can be assigned so in this case we are actually going to use 10.0.6 for our IP addresses so our VPC is going to have these two variable IP addresses so that means we have 255 * 255 amount of
IP addresses to be assignable to VPC so right now we are we aren't actually assigning vpcs we're just assigning the ranges where the IP addresses can actually exist so once we have 10.0.0.0 sl16 we should be good to go to create our VPC all right so we created our VPC we need we're not done yet we can't just put applications or we can't put our server inside this VPC automatically we actually need to go look at our architecture we can see that we are placing our ec2 backend in a public subnet so it's accessible outside
and private subnet is where our RDS is going to exist so we're going to create these subnets which exist in the VPC you need to place items inside a subnet so you can actually use them so let's go to our VPC and by the way the reason why this is complicated it's for security and security for a large application is a huge thing all right I already had some subnets from a previous application so I just ended up deleting those so we are going to create some subnets in our VPC so I'm going to create
subnet I'm going to select the VPC and inside here it's going to give us an option for subnet settings and the first one we are going to create is ru- subnet D1 we're going to choose availability zone of two and over here this is the VPC CER block we're going to leave those blanks and and like before when we mentioned 10 for the subnet cider block instead of this being sl16 we are going to set this to be slash2 or 24 like this so only the last range can go from 200 so 256 sorry not
255 256 IPS are available for us to use so that is good all right so that's our public subnet and we're going to add a new subnet as well and this one is going to be re private D subnet and we're going to write -1 we're going to choose the same availability Zone and over here we are going to do 10.01.01 so that means anything in this public cider block is going to be start with 10.0.0 as locked IP addresses and we can assign anything from 0 to 255 for our public subnet but then for
private it's going to be 10.0.1 point0 so any of those and then after this I'm going to add one more subnet we actually need two private subnets I know over here I know I didn't show it but we actually need two private subnets for RDS that means because we need it for different available availability zone so I'm going to do re private D subnet d two I'm going to choose 2B so this is a different availability Zone the reason why we need different availability zones is just basically they're different data centers or different servers that
will run your private application so if one of them goes down there will be a second one uh available to back it up and you actually need this for our database you actually need two private subnets for database so over here instead of this going to be one this is going to be 2.0 sl24 and that should be good we're creating three subnets so we are going to create that all right so with that you would expect we can just put our applications in our public subnet and private subnet and we should be good actually
not uh it is more confusing than that before we can get to our public subet there's something called the internet gateway for ecy to to be re reached by the entire public so it is kind of annoying but it's all it's all for security purposes um large app large companies like and require uh significant security concerns because of regulations and things like that so over here we're going to create an internet gateway like you saw we're going to do re internet- Gateway and we're just going to create this this is pretty simple and over here
we can just say attach to a VPC and we just select the VPC we created and we're going to attach it now are we done with accessibility no fortunately not we have to set up route tables so route tables are part of the VPC and also part of the subnets so the VPC has a main route table that allows most access but public uh we definitely want a route table for each subnet so we're going to create a public route table that allows access from everywhere and also a private route table that allows access only
from the public subnet so we're going to do just that we're going to go to Route tables but for now let's actually look at how this is configured we're going to go to our vpcs click on VPC ID and you can see right now all of them are configured to this main route table when you create a VPC it's going to automatically create this main route table but we actually don't want to use that we want these route tables to be different for each one for security purposes so we're going to go to our route
tables all right so from here we are going to create a route table and we're going to call this re uh public- route dt-1 we're going to select rvpc and then create route table and then before you move on we're going to do edit submit associations because right now it's not associated so we want the public route table to be associated with the public sub net so I'm going to select this and I'm going to hit save associations we can go back to our route table and you can see we have our uh public route
table and Associated subnet and over here we're just going to change the main one we're just call this call this save so you understand this is the main route table we were talking about and of course you know what we're going to do we're just going to create a route table we are going to go and we are going to write re private route table -1 select the VPC create the route table go to actions hit edit subnet associations we're going to select the private submit -1 save associations we should be good for that one
and then the final thing we are going to create is our another private route table but for the second one so do re private route table-2 select the VPC hit create route table hit actions hit edit subnet associations and click the second one and save associations over here we're going to click hit route table and as you can see we should be able to see all of these route tables and we can double check if everything's routed correctly by clicking your VPC click the VPC ID and you can see we just want to confirm private
subnet is associated with private route table public subnet is associated with the public one and private subnet is associated with private route table and the main one is a lonely guy he's no longer associated with anything he's just the lone main Soul all right so with that our VPC is mostly set up there's actually one last thing we need to do for our route table for our public route table right now it has the same access as the private route table but we actually need to change that so if I go and click uh public
route table we want to hit edit routes right now this is only accessible to local uh anything inside the public subnet those are the only things that can access this current one it doesn't have internet access it's not connected to the internet so the way you need to do this is we're going to add a route and we are going to select this first one 0.0.0.0 sl0 and we're going to hit internet gateway we're going to select the internet gateway that we created and we're going to hit save changes so this will allow for Public
Access so now if you go to our route tables this one is going to have Public Access whereas these two will not which is good for our uh database all right so just to review that all the networking stuff we started with our VPC which created a main route table associated with that and then we also created public subnets and private subnets the subnets are the actual places where we deploy our applications or our AWS services and then we also need an internet gateway if we want public access to a public subnet and then from
there we also needed to configure our public route table so we get Public Access as well private route table is not going to have any access to the outer internet so that's why we did not create internet gateway we also talked about CER block ranges and then public subnets have their own set as well as private subnet will have their own so basically you're assigning IP addresses that the user can use in AWS there is something called knackles and I not going to talk about or I'm not going to show you what those are but
they're basically like a black list of IP addresses where you cannot access whereas public route tables are more like a white list like uh ranges from these domains can access or public can access or private can access those are the things that it talks about whereas knackles which are network access control list which are a different thing and they're much more commonly less used but they're used to do their block certain uh IP addresses and sometimes for like larger Enterprise companies these are very necessary tools that they need because they probably have hundreds of these
applications maybe a thousands of these applications and you need proper networking and even user management control even within the company itself so so there's a lot of networking issues and you might think oh these are not important for me as a developer because applications are all about building applications no for you as a developer your career is dependent on helping like large companies because those are the companies that hire the most so just make sure you understand these kind of things and one last thing I want to talk about for networking is going to be
the security groups security groups are similar to knackles except they're basically associated with with uh individual ads services so you know how knackles are on the subet subnet level security groups are on like a individual AWS service level so they're basically like blacklist for those things and we're going to and it's important for that we're going to be talking about that because if you ever just try to spin up AWS service and you know nothing about deploying applications on AWS you're going to run into Security Group nightmares and they're kind of annoying because they won't
tell you why you're service is not visible on the internet there like you you won't get any kind of warning so it's very important so we'll talk about that all right so we have our networking set up we can finally now go back to our diagram we can actually deploy ec2 which is going to host our backend this is where our node.js application server is going to be running so we can call it like an API endpoint now ec2 is basically just like a server it's like another computer computer that is run in the cloud
basically it's run by AWS they have a bunch of servers that is running a lot of these applications but you can actually run it configure it just like you would do a regular computer it's like hosting on your own computer something like that but most of the time you're just accessing every command via terminal which is the most annoying part you that's why you doesn't feel like another computer but it basically is that's what all it is there's a lot of different options for it but let's get to it we're going to go to ec2
and I'm going to go over launch instance actually we can just go to instances cuz your dashboard might look different so I'm going to create launch instances all right as you can see I already have created it I just did the test run but we're going to create a new one we're going to say launch instance so over here I'm going to call this reor ec2 all right so from here we're going to go down we see quick start we're going to keep it to Amazon Linux which is the default and it is perfect and
from here the machine image we're just going to keep it like this but it says free tier eligible so if you want to check ec2 and the charges and it's important for understanding the AWS charges there is a good location where you can see all the free tier and the details regarding this in this case with ec2 you have 750 hours which represent more than enough hours for a month and by the way this is for free tier account meaning meaning 12 months free so this is 12 months free it doesn't mean it's always free
in this case for example like I guess migration Hub I don't know what that is but 12 months free means for any AWS free tier account you have 750 hours so make sure by the end of 12 months you're accounting for that and also note that 750 hours if you accidentally run two ec2 instances at the same time and you accidentally left it it's going to double the amount of hours so you have to make sure you don't do that as well so only have one instance running so we're going to go back over here
we can see we're can keep everything the same we have a instance type which you can change it if you want more powerful computers but this is the one that's free tier eligible and then over here if you haven't created a new key pair basically it figures out how you can uh connect to your instance you want to make sure you create that So foll the instructions when you create a new key pair and you should be able to be good and over here this is our network settings for our ec2 what we want to
do is we want to click both of these before you hit the edit button over here now the security group before I click the edit button they are the things that are attached to the ec2 and RDS and if you remember they were basically a black list for any IP addresses you don't want accessing the ec2 so that allows for that but for now we are not making this like an Enterprise fully Enterprise application so we're just going to allow any traffic from everywhere so we're going to hit edit and then also we have our
VPC this is our private subnet we actually want to change this to our public subnet make sure that's assigned with that and also Auto assign public IP we want to we want to hit enable and by the way this public IP it says apply charges apply when outside free tier allowance so what this means is that we're using an ipv4 address and they started charge recently ipv4 public ipv4 addresses they are basically charging for that which is a little suspect but this was last year but they do have free hour or free 750 hours meaning
enough for every month you can use one public ipv4 address on your free tier account so that is one account that we will uh use for this ec2 so it will be free as long as you only apply to this particular ec2 instance all right and then from the security group name we are just going to call this reor ec2 DSG I'm going to copy this paste it in the description over here for the created just so it's there and here we have our security group rules we have inbound meaning anywhere from SSH type calls
and then https calls http P calls with TCP protocol all of them can access our ec2 which is good configure storage we can just leave it the default and then finally we can hit launch instance all right from there once it succeeds we're going to go back to our instances and you should be able to see actually we should refresh the page we should be able to see the ec2 that we created so over here if it says running that means your ec2 is running sometimes it might take some time if it's just pending or
something you're going to have to wait a little bit until it gets to running State now over here in our instance ID we're going to now click on the instance ID what this allows us to do is we can now connect to our ec2 instance via ec2 instance connect so basically we can use this uh computer and run commands on the computer via terminal commands so right here we're just going to keep everything by default and we're going to hit connect all right so in our terminal now we can actually access our ec2 which is
pretty cool now there's a link in the description that will show and walk you through every step of the process for ec2 setup so we're going to do just exactly that and we're going to start with pseudo su- like so which will switch to a super user and we are also going to install NVM so what we need to do is install NVM and node on this computer so we're we're going to run through all the commands that are required for installing node so all of this there's a lot of steps but it's basically we're
just installing node and NVM on this application so over here there's a command curl Das uh o you can either copy it from that uh link that I showed you or we can just you can just copy it from here and we're going to activate NVM via this command and then install the latest version of node using NVM and we're just going to check if it's fully installed so we're going to run n node DV and also npm Das so if you have that that should be good all right the next thing is we're going
to be installing git and we're going to clone the repository from our GitHub that we pushed up a while back so we can install the actual application onto This Server so the first thing I'm going to do is Pudo yum update Dy make sure everything is updated and then we're going to install git via that command that you saw and we're just going to check if git was installed with g-- version and that is good and then from here we're going to do git clone and we're going to copy the actual uh GitHub repo that
we created earlier so I'm going to go over here copy that and then go back to our instance paste it over here and we can hit enter now our application is now existent on our computer and we're going to write LS so you can see that we have the folder it created so we're going to go CD real estate-pr and then we can write LS we can see that we should have our server and client which we do we're going to go to CD server we don't need the client in this case but we are
going to run npmi all right so from here we should be feasibly allowed to run our server so I'm going to run npm run Dev just to double check so now it says server runting on Port 3002 which is consistent with what we are been setting but there is a problem if you go back to instance details we go to security and then we go down we see our security group inbound rules which we set up earlier the port that we are allowing into our ec2 is 22 443 and 80 but nowhere does it say
3, two so we actually need to change these ports and we want to change the port to 80 so we're going to go back to our ec2 instance connect and we're going to cancel out like we normally do contrl c so if you remember with our EMV uh file we can change the port that we want and just note that the port has or the EnV variable is not created because we didn't push it up into our GitHub re repo for security reasons so we what we want to do is do Echo uh PRS or
not PRS uh double quotation Port is equal to 80 uh greater than equal sign or greater than sign and then EnV so we're going to do that and we're going to create an variable variable and we're going to do LS to see if it created it and I guess maybe it doesn't show it over here we're going to try running npm runev one last time and with that we should be able to run on Port 80 which is good all right so our server is running how do we test test it so if we want
to check if we can actually get information we can go back to our instance details and it says Auto assigned IP address remember this is the public IP address that we have created we can hit open address now over here it's not going to go to the actual linkins you're going to get into this infinite Loop and it's not going when that happens it means it's not working and the that's the annoying thing about AWS and when you deal with networking you're not going to get easy ISS easy results from dealing with stuff like that
so instead we're going to go back and as you can see we have we already have the IP address instead of https which we have not configured yet we're going to deal with that with API Gateway we're going to remove the S and hit this uh IP address and you can see This is Home Route that is the endpoint that we created for our home URL so if you remember way back when in our application we wrote this uh route for the home address this is Home Route we can see that it's working for HTTP
it's not secure but we have the endpoint that means our backend is fully working and yes we are still not done obviously but just congrat yourself on the back because this is already a very difficult task to do for AWS and not a lot of people can do this so this is very very good okay so from here let's go back to our connect and as you can see we have our endpoints being run meaning these are the times that the IP address have connected to the ec2 and then we can just see if we
refresh the page we should see another log and we get 304 which means everything is working perfectly so from here this is fine and good but what if the ec2 disconnects or some something happen happens it crashes and it restarts the application that means your server actually goes down but there's actually something that uh handles these scenarios and that's called pm2 This is Advanced production process manager for node.js it's a Damon process manager that will help you manage and keep your application online 24/7 for node.js so we're going to use something like this on our
application and it should be relatively straightforward um it's going to provide a lot of extra tools and I'll look looks pretty cool and you're going to have something very production level all right so to do this we're just going to cancel out our server and I'm going to run npmi pm2 DG so we're going to install pm2 globally and it should be working and then from here if you wanted to but we actually created this Nano ecosystem config so Nano Eco system. config.js if you want to edit the file that we already created a while
back we have this file called I actually call this project management because I was using this as a reference we can actually just change this we can just change this to real estate and we can just hit command X and we can just say y command C and command X and just hit enter after we save it so it should be good when we save this and then from here we're going to run a bit of a command so so we're going to run pseudo EnV path is equal to path which node which pm2 startup
so anytime the system startups we can run this command and it's going to rerun our node application anytime that happens when s system reboots so we're going to hit that enter and it should be good going to run all of these things and then from here we can just run pm2 start ecosystem . config.js so that was the purpose of and it seems like when I try to do pm2 start ecosystem config we get error no script path but I believe I know why so let's actually write uh Nano ecosystem. config.js I did forget an
export S I think in the final project I may have fixed this so make sure actually not that it will probably be fixed in the real application so I'm going to keep this like this hit real estate like that save it and hit enter actually I might just keep it like this just so you guys can see and modify it yourself so I'm going to do ecosystem. config.js and there we go there we go we we got it working got me a little worried for a sec but with pm2 you have a lot of cool
commands so let's start with doing pm2 monit so if I run that we can see our real estate logs we have a lot of extra information if you ever want to check if I refresh it and I go over here you can see the get request it's happening over here which is very nice um we can cancel out using contrl C we can also do pm2 stop all that means it will just stop the application that we are running or we can just do pm2 delete uh all like this and I'll delete and as you
can see there's no more application running we're going to pm2 status which will show the version that we are running but we can go back and run our application once again we can do ecosystem. config.js and run our application and monitor it if we if we would like all right so we successfully created our ec2 and it's running and everything is uh fine and dandy but we need to go to the next step which is our RDS so RDS the ec2 needs to connect to our RDS which is our database and that should be pretty
straightforward with some caveats so over here we're just going to keep this and we're going to keep this instance details open so I'm going to just rightclick open link in a new tab for AWS console and we're just going to go to RDS so one thing to know about RDS is that whereas ec2 we just needed one public subnet RDS requires at least two private subnets it needs two availability zones for those private subnets and basically it allows you to just in case if the RDS goes down you have some kind of backup just in
case and they forcefully do this for you so we're going to go back we're going to go to databases for RDS and we're going to hit create database and over here here we have the option for easy create which would make a lot easier for you as a developer but standard create is going to be a better option for us just to make sure that we don't get charged for any um anything that might secretly charge us for on AWS so we want to do standard create so we're going to get more flexible options of
controlling the cost that we use so over here we have Aurora but we want to actually choose postgressql which is um Aurora is like a different service we're going to keep it to post Christ to keep it simple and by the way if you go back to our uh free tier service RDS gives us 12 months free 750 hours so one month use and again don't run two RDS just in case you have those issues all right so over here we have template and we are obviously going to choose the free tier so we don't
get a charge this will be by default uh removed but in this case for DB instance uh identifier I'm going to call this re- um RDS the reason why I didn't do underscore this time because they don't allow it in the database instance identifier I'm not exactly sure why but um we're going to label it like that over here with the master username again this is going to be something we are going to be using in our uh database URL so make sure you note this postgress so keep that as a master username and note
that and over here don't do manage and a Secrets manager that will be secure but we're not going to do that we're going to do self-managed and for the master password keep note of this because this is again going to be used as your uh database URL that we need but I'm going to just say hello uh hello with capitalize H my friend 1 2 3 4 and you can call it whatever you want but I'm using this just so it's easy for me to remember and it's also pretty secure but just realize that we're
going to be using this in our database URL like we did before remember in our local database long time ago we set that up all right and then over here instance configuration we can leave it to default go over here general purpose allocated storage this is all fine but over here additional storage configuration we're going to just disable storage autoscaling just in case we don't get just in case we get we might get charged for that so we want to keep it off all right and then we're just going to hit don't connect to an
ec2 compute resource we're going to make sure we are in the right subnets with three subnets and two availability zones and over here if you didn't have two private uh subnets this option wouldn't be able wouldn't exist because they want you to create a DB subnet group but that requires us to have two private subnets so if you didn't create two private subnets this option wouldn't exist so we want to um we want to create that before we create the database and then there's a public access we definitely do not want to assign a public
IP address if you remember I said one public IP address is free and that's going to be for ec2 but not for our database so this one needs to be private and over here instead of choosing existing VPC security groups we want to create a new one specifically for RDS and I'm going to call this rore RDS Das SG and the availability Zone we're just going to choose 2A doesn't matter all right and then from here we can just keep everything by default including the additional configuration and over here we're going to turn off performance
insides because it's one of those things you could potentially get charged to as well as additional configur ation you want to change this initial database name we're just going to call this real estate like so like that and also do not enable automated backups in this case otherwise you might get charged as well as enable encryption I got charged for uh backup a long time ago when I didn't realize somehow the backup exceeded my storage limit for some weird reason I didn't understand it and from here we can just keep everything the default and over
here RDS free is available to you for 12 months so it shows you that we have the free tier available like this so from here we should now be able to create our database and there you go we should be able to see that we are creating the database and we should see the status of creating so that should be good for now all right so from here we have our um security groups attached but we do need to make a few settings change so over here we have VPC security groups for this RDS but
right now we want access from the ec2 to this RDS and we need to go into our security groups I'm going to click this Security Group I'm going to hit edit inbound rules right now it cannot the ec2 cannot access the postgress because we need to add a rule specifically from the postgress so I'm going to go down click postgressql and over here we're going to go all the way down and we're going to see that we have re ec2 Security Group this is Security Group I I did change the name accidentally but Security Group
is the name we're going to select that and that should be the postest um access for the ec2 if we save the rules so now that security group has access to this postgress RDS table so so that will allow us to connect so we did that for the RDS and just to double check we actually want to go to our ec2 and go to our ec2 instance and we want to change the outbound of this ec2 so if we go to the ec2 instance that we created we're going to go over here we're going to
go to security we see our security over here and we want to click the security group that we have over here and then when when we are at the security group we want to hit outbound rules once we are here we're going to select edit outbound security groups all have inbound and outbound like we just saw RDS needs to be able to uh receive inputs from the ec2 so that's why we changed the inbound but ec2 needs to send outbound calls to RDS so that is exactly what we're going to ch change so we're going
to go over here and I added the rule and we're going to go to postgressql select that and we want to select um RDS Security Group and I'm going to hit save rule so now that should allow us to access it potentially this one that says all traffic will allow it anyways but just to just to double check that we have access to that Security Group so now we have access via networking issues but the the main part that we need to do is in our E2 server we actually need to add a way to
connect to our database via the environment variable if you remember way back in our server we had this database URL this database URL here in this case connected to our local database but in our real application this is going to connect to our production level remember I told you to note the master username and as well as the database name things like that those are going to be useful all right so we we'll reconstruct this with the new database URL that we're going to use so over here remember the master username is going to be
postgress as 1 2 3 4 is the password but in our case the password was hello my friend 1 2 3 4 I capitalize it make sure if you didn't capitalize it it's lowercase so it's dependent on you for the Local Host you want to change this to be the URL for the RDS so if we go back to RDS a lot of the information that we need is there so I'm going to go to databases click on re- RDS and you see this endpoint that's the endp point we're going to be using for so
I'm going to copy that paste it over here in the Local Host that's the endpoint that we need the port is 5432 and this database name is going to be the database name we configured as well so if you go to configuration it has a lot of the information we need and includes the database name which was real estate which we configured so real estate is going to be there in this case there's no two and this is the database URL we need to configure on our ec2 instance so this needs to be changed in
the environment very variable so I'm going to just go over here I'm going to copy this entire line I'm going to cut it because I don't want to change the local um and go back to our ec2 instance connect I'm going to do pm2 delete all because we don't want that we want to do Nano Dov change the environment variable and over here on our new line I'm going to paste what we wrote with database URL all right once we have that I'm going to hit control o contrl s all right that is good for
environment variable but remember we didn't set up our database so we need to run the Prisma commands so just bear with me we're almost there so we just have to run npm run Prisma colon generate if you remember that's going to run our Prisma generation of our database and then I'm going to run npx Prisma migrate Dev d-name init and I'm going to run mpm run seed all right and then it should be able to seed our database all right and that's good and then we can do pm2 start ecosystem. config.js to start it up
again I'm just going to do pm2 minut so we can monitor it and over over here in our instance details it's compiling so let's wait a little bit all right so we're running on Port 80 so let's go back to our ec2 instance which I still have it open so I'm going to open the address and again it's going to be https we're going to change it to http go to it we see our home route but now we want to check if our data exists so the easiest public publicly accessible route is going to
be properties so let's try that and there you go there you go I have a pretty pin vs code U Chrome extension that allows me to see all the properties and this is every property existing in our database so that means our backend is fully working connected to our ec2 and you have no problems and if you get this far just congrat congratulate yourself put your p on your back because this is this is not easy stuff not easy stuff to get to this point you're probably going to run into some weird bugs but that's
also the process of learning as a developer so make sure you get through those and double check every nook and cranny that you have set up everything all right so I'm going to close this out a little bit close clean this up so I I don't have as many tabs um the next part is going to be a little more simpler we're going to handle the amplify amplify is for hosting nextjs it's similar to versell but it's aws's version I know vel's version is most likely better than AWS a aws's version but this is the
one we want to keep in awvs a lot of times you can if you want you can put and use versell to host your nextjs application but uh keeping it all within AWS is generally more helpful so you keep it confined to one cloud provider in a future video though amplify manages all the uh under the hood stuff that a uh nextjs is kind of doing when they're deploying a production level you know nextjs application it's all abstracted away but the problem is the cost but in a future video I'm going to show you how
to do all of the stuff that amplify is doing under the hood and we're going to create our own you know production level deployment of next JS because this will be important and this is not something that I I just want to know and flex on you guys that you guys should know this but I have had to try and figure this out myself for actual companies they want this to be deployed in production level settings so it is important to know how it works and how it gets deployed because what verell is doing is
not magic there's a lot of things that they're doing behind the scenes to deploy nextjs so we'll be going through that in a future video all right so in our case we're going to go back to our AWS we're going to go to amplify select that all right you should be greeted with this page now this is the amplify where you're actually deploying kind of like any type of web app um mobile app nextjs type applications you can deploy it and adus is basically managing it for you so it's just as abstracted as Rell is
doing it but this is an easy way to host our nextjs application so let's just do that so we're going to hit deploy an app we're going to hit GitHub and we're going to hit next now what you probably will see is that mine's already connected here but for yours you might it might ask you to connect to your GitHub account so you're going to have to connect to your GitHub account so we can add the repository so make sure you do that you're you're going to have to make sure you have the correct GitHub
permissions for a specific repository I suggest you add specific repositories as needed all right from there make sure you add the correct repo M's real estate-pr and I'm going to use the master as the main one and since our app includes both client and server we're going to say my app is a mono repo and what we want to write is client over here for the mono repo rout directory and we're going to hit next and if successful it should show that it auto detected the framework of next JF and it'll give you all all
the defaults we can keep this the same and we keep create and use a new service Rule and for the advanced settings we can add some environment variables all right so the API URLs we're going to do next public API base URL something like this and also this value before we had Local Host 3001 but this is not correct because that's for a local host our API base URL is going to be where our ec2 instance is so I'm going to open a link in new tab we're going to go to ec2 and go back
to our instance and you can see in our instance we have the public ipv4 address we're going to copy that and we're going to paste it over here and make sure HTTP colon SL slash like this so This actually won't work and I'll tell you why because of security reasons when you do like cross browser or cross server connections like this HTTP won't work but we're going to do a different way of handling this type of request but for now we're going to keep it like that and then from here we also need to add
the mapbox access token as well as the Cognito IDs so let's do that so over here in mymv client I'm just going to copy this over with public map box access token and I'm going to copy the access token over here and I'm going to add a new one I'm going to add the AWS Cognito user pool ID as well paste that over there copy this add the pool ID and then the client ID as well make sure we copy that and make sure you like copy paste it if you copy paste it you're not
going to run into uh typo errors it's a very important thing like you can type it as well but you might run into WR writing it incorrectly especially for environment variables it's a hassle if you don't and also I think there's kind of like a little weird bug we just want to make sure we hit the add new and delete because I don't know I think it might not work and then we can finally hit and over here I'm going to hit save and deploy and before I forget by the way for the free tier
AWS amplify hosting they have 15 gigabyt serve per month so if someone's constantly hitting your amplify hosting and you have more than 15 gigabytes um then you're going to be charged but this should be good enough for our application for sure all right with that once it's deployed you can hit visit deployed URL and you should be able to see your application front end now the only problem is when we try to make an API request to our back end there's going to be a problem this is being hosted on https while our ec2 instance
is hosted on HTTP so the problem is when you try to make an request to http back end it's going to run into a problem called blocked mixed content for um browsers they they blocked this so the way to get around this you can do um the complicated https certificates and you can manage it yourself but that's very complicated so a good way to work around this is API Gateway it's a service that allows you to automatically set up the https and you can set up your backend routes via um API Gateway so we're going
to go create a new AWS over here and we are going to go to API Gateway all right just real quick for API Gateway you have 1 million API calls received per month so most likely if you're just publishing it for your portfolio this is you're probably not going to receive this free tier 12 months free so again it's pretty generous for the free tier so let's go back to our API Gateway and you'll be able to see a page like this now HTTP API you can do something like like this but this is not
what we want we want to be able to use Cognito um authorizers so we're going to use rest API over here so we're going to hit build now again before I go you can see in my diagram AWS amplify it's going to make a request to API Gateway which will allow us to connect through https to our ec2 backend so let's go back to our API Gateway we're going to create a new API we're going to call this re api-gateway we don't need a description we could just say create API all right the main problem
with setting up these resources the resources are just a single endpoint for example /properties and then we have SL propertyid and then we have all of these very complex routing that we have over here with you know slash you know/ leases and then applications get we could set up all of this manually inside side here through every single resource but that is quite tedious so we're going to do something with proxies so over here we want to select proxy resource this will allow us in API Gateway will forward all the request to our back end
so usually API Gateway has this you know it is basically like a Gateway it first when AWS amplify sees the request it will do what it needs to and Route you to the correct locations on your back end but in this case we're sending all the requests we're forwarding it to our ec2 for all the proxies or for all the routes and making our ec2 handle that instead because that makes it a lot easier for our Express to handle it so over here I'm going to set proxy plus like so close that and hit cores
and we're going to create the resource and make sure you have it named as/ proxy plus like that and then over here you want to select the any and we're we're going to hit edit integration inside here we're going to select HTTP and then from here we're going to select htt proxy integration we want to select any and for the endpoint URL is going to be the ec2 instance URL that we want so if I go back over here we're going to grab this public ipv4 address we're going to paste it over here with make
sure you have HTTP colon SL slash like this and then also you want to add SL flash par or curly braces Pro proxy like this or else it's not going to work and then from here we're going to hit save all right from here we're then going to create something called a Cognito authorizer so this allows Cognito to authorize your API calls that you make from the front end to the back end so what we do is we go to authorizers we hit create an authorizer we're going to call this um re API Gateway Cognito
Das authorizer and what we want to do is uh click Cognito and we want to make sure we choose the Cognito user pool so I'm going to select the Cognito user pool whatever you named it and the token source and over here in the token Source we're going to say authorization we're going to leave token validation optional and we're just going to hit create authorizer and then we go back to our resources click any and we're going to go to Method request settings and we're going to hit edit inside here we want to choose our
Cognito authorizer that we created and we're just going to leave it like this and we're just going to hit save so this one has Cognito authorizer authentication all right but there's also one problem is that /properties is a public resource but the Cognito authorizer is applying to every single route in our application but we don't want authentication for property so if you look back go to our property routes this these two do not have any uh authorization so what we want to do is go back to our create resource and we're just going to create
another resource but this time we're not going to do proxy resource we're going to choose the slash with no proxy and we're just going to say properties and we're going to hit the course like this and we're going to hit create resource and over here I want to create a method we're going to select method type of get click HTTP HTTP proxy integration select get the Endo is going to be the same over here we're copying this paste it over here with HTTP colon slash and then do slash properties we're going to leave everything the
same and hit create method and with all of this let's actually deploy our API we're going to select new stage and we're going to call this prod and hit deploy and with that this is the invoke URL this deployment is active we're going to hit copy go to a new tab go select this it's going to say missing authentication token but let's try go to properties and as you can see our properties Ando works perfectly if I try to go to leases which is authentication it says says unauthorized which is exactly what we expect so
yeah that is perfectly good all right with that confirmed let's actually copy this and then now we can go back to our amplify go to app settings general settings actually hosting we should go to environment variables and we can do manage variables and then we can go to public API Bas URL we can replace it with our HTTP value with prod we're going to hit save the environment variable is deployed and over here the changes aren't updated automatically so we need to click on the deployment and select redeploy this version and wait for this to
finish once that's done we can go to Real Estate prod and you can see visit we can try and visit our deployed URL and let's try signing in once you're signed in we can now go to/ search and as you can see the API calls are working perfectly so let's take a look there are some issues over there but those are from map blocks I don't exactly know how to fix those but if we go over here we find this one property's location we now know that it's going to the correct endpoint with properties location
and everything is working fully as expected and it looks very nice look at this look at this map I don't know I really like this new version any go to go go to dashboard and you can see that we have no nothing favored it for this particular user but everything works as expected and it's pretty quite fast and that's it for amplify API Gateway everything works our front end application the last thing is going to be S3 we're going to go through this very quick there's only one thing that we want to do really with
it all right so the last thing is uh S3 images I'm not going to cover all the ways that you want to add all the S3 images onto our application because this is getting quite long I'm just going to do create bucket this is our S3 by the way I searched it up via S3 like this so make sure you click on that inside here we're going to do general purpose bucket name will be re S3 images like so I think this one doesn't allow underscore so we're just going to keep it like this we're
going to have acl's disabled acl's is something specific to S3 buckets it's another form of like Knack again like a blocklist but this is kind of deprecated so don't use ACLS it's very it's sounds similar to knackles but this is specifically for um S3 and then over here with the block Public Access we actually want to disable this we want Public Access and we're just going to say I acknowledge so this is Public Access images should be available everywhere so we're not going to have any of that we're going to keep everything the same over
here and we're just going to hit create bucket and then we're going to once we created it we're going to click the rees3 images we're going to hit permissions and right here we have block called Public Access and it's kind of annoying for bucket policy we actually need to set this so that everyone can access this so we're going to hit edit and this is a policy that we basically need to write so what I'm going to do is I'm going to add version like this with colon 20 2012 10-17 I'm just going to write
whatever because or I'm going to use the one that I've I know works you could um edit the statement and make sure it works there like adding new statement from there but I'm just going to use the one that actually works and you can get this from the documentation so in our statement we're going to do Sid colon statement one comma effect colon allow comma principal colon star like this action actually this needs to be capitalized action colon S3 colon get object comma resource colon and we need to grab this bucket ar ar n so
I'm going to put this in quotations and then after this this you have to write slash star make sure you add this slash star after you copy this bucket Arn for the resource this is a way so that we have uh policies that allow different access rights for different services so in this case this is basically allow um allow everything to access it essentially since these images are not private we're just going to keep it open so that is our permissions and then from here in our objects we're just going to upload all the files
in our public directory of our application that we created so if you wanted I'm not going to do it in our application if you wanted if you remember our client directory we have a public folder with all the images you can Source all those images instead of um putting it in the nextjs amplify section because nextjs knows to Source this you can instead put it on to S3 if you wanted to is there any advantage of doing that I'm not exactly sure I don't think so but if you have lots of images then it becomes
a problem so anyways you can just drag it over here and you can just hit upload and again if you take a look free tier um 5 gbyte is free for 12 months again free tier so make sure you're on the free tier you get 5 gabes for this all right once that's finished we can hit close go back to our uh objects and we'll be able to see this all right there's actually one thing we left a while back and I did forget to uncomment this out but if you go back to our code
in our properties controller we actually have in create property we commented the photo URLs out so when we create a property we need to upload the images and there is a section where we had photo URLs so we want to uncomment this section out and we also want to uncomment the section over here so it adds the photo URLs in our new property and over here we do have an S3 bucket name now we don't need to create this in EnV if we don't want to but we might as well let's just do S3 bucket
name and we can say your bucket name here something like this now this is not the correct one but this is only local so right now it doesn't go to an S3 bucket so this will basically fail um but we can put this EnV inside our ec2 instance where we have the environment variables there so before we do that let's actually what I want to do is add this to our repo before I forget just so you have the final version um S3 bucket and actually no there's there actually before I do that before I
do that one more thing next doc config right here we actually need to be able to provide access for um AWS images as well so we're going to do protocol called in HTTPS so by the way this is in the front end host name I'm not sure it's kind of annoying to add these access we're just going to allow anything from amazon.com we're going to do Port like this and path Name colon SL star star like this I'm going to do G add. git commit DM image images final adjustment and get push origin master so
we'll have all the images and we'll be able to upload it into our bucket and we're going to go back over here now we do need to go back to our ec2 instance I'm going to go out of this I'm going to do pm2 delete all I'm going to do Nano dot I did realize that if we when we make changes like this right here when we make changes to the repo it's unfortunate that if we do something we change the server we actually need to pull the repo so I need to go back and
there's kind of annoying issue with this so I'm going to do um and because I updated the GitHub repo I can just do I go back to the main one real estate-pr which is where our git index uh exist I'm going to do git pull origin master and actually let's do get stash because it's going to block me I'm going to do get stash and then I'm going to do get pull origin master and let's actually see we're going to do LS we can see the changes that we have made to our files which is
good we're going to go to our server we're going to do LS I want to double check if our ecosystem. config.js is correct okay the module export so okay that is correct we're going to exit out of that we're going to see if nan. EMV exists and oh it does it seems to exist not exactly sure it didn't pulled different changes but anyways we need to go Tov and over here on this new line we are going to do S3 uncore bucket URL actually bucket name sorry bucket name is equal to and what we need
is the rees3 images which is the bucket name we are going to add that over here and we can put this in strings as well and we're going to do crl o contrl s and then crl X let me just double check that it actually saved because I have issues okay and then from there I can do pm2 start ecosystem. config.js and that should feasibly give us the last changes we basically needed and we're just going to do a little quick check because once we push it up to AWS amplify it's going to redeploy and
I believe I don't know if it's the same URL but let's sign in yeah it had some issues before if we go to dashboard we're we should be able to see that we have all of this we can search our properties and everything should be good now if you wanted you can add all the images and change it for each uh property I just didn't get around to have time for that but everything looks pretty good everything should be working as expected and there you go we finished another great large Enterprise level application this time
focusing on maps I really wanted to focus on map Maps so that in the future we can run and do a lot of these map type applications for Enterprise level and also I hope you enjoyed that I've got around doing Cognito and everything works this time with the roles and the different splits of roles and we have sign in sign up Pages we also have a very detailed diagram of everything that we have covered so yeah I hope you enjoyed this application just congratulate yourself again if you've gone all the way through this video not
many people do but what you have created was a full Enterprise level application and you have probably learned so so much stay tuned I have a lot of other content that's coming it's taking some time but I'm starting to get a nice flow and process to all of this so stay tuned like comment and subscribe and thanks for watching
Related Videos
NextJS Full Course: Build a Car Dealer CMS (Part 1/3)
8:41:05
NextJS Full Course: Build a Car Dealer CMS...
Taylor Lindores-Reeves
21,165 views
Jon Stewart on Which Speech Is Free and Which Will Cost You in Trump’s America | The Daily Show
19:36
Jon Stewart on Which Speech Is Free and Wh...
The Daily Show
1,728,637 views
🚀 Local Server Setup 2024: Test Websites Like a Pro (IDE & Text Editor Guide!)
4:59
🚀 Local Server Setup 2024: Test Websites ...
Glams Era
No views
Music for Work — Deep Focus Mix for Programming, Coding
1:29:35
Music for Work — Deep Focus Mix for Progra...
Chill Music Lab
3,547,356 views
Next.js 15 Full Tutorial - Beginner to Advanced
6:54:09
Next.js 15 Full Tutorial - Beginner to Adv...
Codevolution
57,661 views
Build and Deploy a Full-Stack Video Conferencing App using NextJS 15, TypeScript, TailwindCSS & more
3:10:44
Build and Deploy a Full-Stack Video Confer...
Programming Fluency 🧑‍💻
1,274 views
Snow White is AWFUL - The FOULEST of Them All
17:12
Snow White is AWFUL - The FOULEST of Them All
Nerdrotic
833,590 views
Pro Economist Vs Cities Skylines 2 - The Perfect NEGATIVE TAX City
30:03
Pro Economist Vs Cities Skylines 2 - The P...
The Spiffing Brit
503,226 views
Best programming languages in 2025 | ThePrimeagen and Lex Fridman
21:31
Best programming languages in 2025 | ThePr...
Lex Clips
56,315 views
lofi hip hop radio 📚 beats to relax/study to
lofi hip hop radio 📚 beats to relax/study to
Lofi Girl
Node.js: The Documentary | An origin story
1:02:49
Node.js: The Documentary | An origin story
Honeypot
706,697 views
The Only CSS Layout Guide You'll Ever Need
24:22
The Only CSS Layout Guide You'll Ever Need
EdRoh
273,265 views
Deep & Melodic House 24/7: Relaxing Music • Chill Study Music
Deep & Melodic House 24/7: Relaxing Music ...
Monstercat Silk
Build an Invoice App with Next.js 15
4:34:24
Build an Invoice App with Next.js 15
Colby Fayock
78,362 views
ADHD Relief Music: Studying Music for Better Concentration and Focus, Study Music
7:47:08
ADHD Relief Music: Studying Music for Bett...
Greenred Productions - Relaxing Music
10,510,352 views
10 Years Later: Software Opinions I’ve Completely Changed
26:26
10 Years Later: Software Opinions I’ve Com...
ThePrimeTime
248,396 views
John Bolton reacts to news of Trump officials texting war plans to reporter
7:47
John Bolton reacts to news of Trump offici...
CNN
1,184,173 views
Next.js 15 MySQL Social X App Tutorial w Real-Time Notifications | Full-Stack Social Media Socket.io
4:22:26
Next.js 15 MySQL Social X App Tutorial w R...
Lama Dev
23,315 views
Team Trump Accidentally Texts War Plans, Donald Throws Fit Over Portrait & Guillermo in White Lotus
14:33
Team Trump Accidentally Texts War Plans, D...
Jimmy Kimmel Live
1,258,698 views
Complete Backend Course | Build and Deploy Your First Production-Ready API
3:08:42
Complete Backend Course | Build and Deploy...
JavaScript Mastery
424,602 views
Copyright © 2025. Made with ♥ in London by YTScribe.com