Build and Deploy a React Admin Dashboard With Real time Data, Charts, Events, Kanban, CRM, and More

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
do you want to develop a react admin dashboard that updates in real time across devices hi there and welcome to another Project based tutorial where you'll build an admin dashboard with full authentication including forgotten password a homepage showcasing charts upcoming events and latest activities a comprehensive table for companies with full crud operations and search capabilities a full crud can ban board Bo with multiple asses and deadlines that shift automatically and for everything mentioned so far real time synchronization for lightning fast updates like in a real world admin dashboard you'll build and learn all these features using react graphql typescript and design and refine and before we dive into the development let's see how the app works we have this good-looking login where you can input your details if you put something wrong you'll see a toast on the top I will now use the right credentials and there we go we're in did you see that that subtle smooth chart animation Let me refresh and show it to you again how nice we can also see deals lost and won in that month on that chart on the left side we also have upcoming events and below that our latest activities all coming from the back end on the company's page you'll see a list of all the companies we've closed deals with or that are currently in progress if you need to find something specific there's a handy pagination feature and a search option for the company title now when it comes to managing these companies the power is in your hands you can view and edit their details check out the associated leads and even perform targeted searches within the lead section and hey if you're done with a company you can easily delete it over here at the top we can register a new company now check this out I'll open the same site in two browsers create a company in one and Bam changes happen instantly in the other no need to refresh and it's not just about creating stuff it works for any changes you make in the app edits deletes moves drag and drop you name it it's all about keeping things seamless efficient and real time as they should be next we have a complex Canan board that could be a whole app in and of itself like Trello or jira here we use it to handle all internal company tasks easily drag and drop tasks check deadlines and tweak details by assigning to others adjusting dates marking as complete or removing from the list entirely you can also create these tasks in real time and modify all the details from the title description and date that changes colors according to how close it is to the deadline with the ability to have multiple assignes on the same task you can also modify your account details from here everything you see works well on any device giving you a smooth experience whether you're on your computer tablet or phone and all of this was made possible by refine without which building this powerful dashboard would have been a long and difficult task with refine we can rapidly develop many kinds of web apps like internal tools admin panels B2B apps dashboards and any type of crud application what makes refine special is that it comes packed with readyto ous hooks and components this means faster development because you don't waste time on repetitive tasks using this modern hook based architecture and a system of providers we can Implement all industry standard Solutions required for a project like authentication roles routing networking State Management and even internationalization all in the simplest way possible and it's not just me who thinks this way refine has become the fifth most used technology in the react ecosystem right after nextjs and zustand now you may wonder about the prerequisites for this tutorial all you need is a good grasp of JavaScript and react and if you don't have it yet don't fret check out the crash courses on YouTube to get up to speed so so without further Ado let's dive right into the code to get started building our amazing dashboard you can open up an empty Visual Studio code window and then open up the terminal then run the command mpm create refine Das app at latest and press enter it's going to ask you whether you want to install the create refine app to which we're going to say why as in yes it's going to take a moment and immediately after we got this great animation they said make it work make it right or make it fast with refine we're already there okay that's a nice touch now the remote Source has been downloaded successfully and we can choose a project template in this case we're going to proceed with vit as we don't necessarily need many built-in benefits that nextjs provides of course if you want to you can always switch it up later or you can try it on your own by building a nextjs version of this project anyway let's proceed with vit the name for our project can be the default name that they provide heavy bat sort and here we can choose what do we want to use for our backend service you have many options such as rest API nestjs graphql strappy superbase Medusa anything you might need in this case we can proceed with nestjs as there are some specific things I want to teach you next we have to choose a UI framework now we have a lot of options to choose from you can go headless and then do whatever you want but in this case I'm going to go with ADD design as I think it fits this dashboard theme very well for the authentication logic we're going to go with the custom mock o provider in this case we won't be needing internationalization and here if you want to you can give them your email such as contact JS mastery. proo and press enter next all of the packages are going to be installed based off of the decisions that you've made in the CLI installation process so pause this video give it a few moments and I'll be right back and there we go to start developing we can CD into the folder name heavy bat sort and I would highly recommend that you press and hold controller command and then join refines Discord server this is the best place to get your questions answered and your bugs resolved once you join the Discord server we want to open up this directory within our Visual Studio codee as we're not there yet so hold control or command and then click right here it should open it up right away or just find the folder manually and drag and drop it into your Visual Studio code window once we're here let's open up the terminal and run mpmi to install all the necessary dependencies and then mpm run Dev to get things going immediately we can see that we can again get help from the refine team and we are live on Local Host 5173 there we go welcome aboard configuration is completed we have the docs tutorials examples and Community it is looking great you might have spotted a small refine element that's refine step tools and it's here to improve our experience while developing to see how it helps let's click on it and expand it to see it in its full mode it'll prompt us to sign in to view the content so just make an account using any social odd provider and here we go while it's still in beta there are two major features released the first feature is the package overview it shows us all of the refine related packages in our app but it also lets us update those packages if newer versions are out luckily as of this recording we're using the latest versions so no updates are needed but keep an eye on it while working on the project if there's an update hit the button and you will be set with latest packages and their dependencies now the second feature I like is called monitoring click on it and you'll see your apps queries and mutations used via hooks you can see if they succeeded failed or what kind of info They're bringing back all in one place currently there might be nothing visible because we haven't set up anything yet but if I tweak the filters here and include both data and O will start seeing something like this we can see the two hooks we have initialized before if you click on it you'll get additional details about the hook you'll also notice there are three upcoming features playground inference preview and an AI assistant so keep an eye on them as they seem quite promising for now let's continue with our app and we'll later see how this tool truly works when we start implementing some features but now we have to turn this into a real dashboard and to do that we'll first start by exploring our existing codebase of course everything is within the source folder here we have our components such as the header and the index exporting it we have our context for de Coler modes and we have our Pages we also have our odd provider and more but in this case we want to remove almost everything we were given at the start and we want to start from the bare Beginnings so let's remove the components folder by deleting it the context as well and finally the O provider to then if we go into the app. TSX we'll see that we have some errors so of course we have to remove the Imports as well as removing all of the places where those Imports were mentioned such as in this Coler mode context as well as in this o provider right here which for now we can comment out next we want to remove all of these Imports as well as the references to those Imports so let's comment out these right here and as you can see refine will complain as its typescript interfaces know that it's missing the specific type but don't worry we're going to create all of these providers in separate files providers are refines building blocks that help you manage different aspects of the application such as data fetching authentication routing notifications realtime updates and more data provider in this case case deals with getting data from the server and doing things like adding changing or deleting data it also handles caching like storing information temporarily and making sure everything is up to date a typical data provider workflow looks like this you can connect your API to the data provider and it'll handle the rest by making HTTP requests or caching data in our app we'll set up a data provider that syncs our graphql API via a graphql client we'll take it a step further by creating a custom data fetch function this function allows us to set headers and handle errors efficiently it acts as a wrapper around the core fetch function you can also think of it as middleware this way we avoid scattering TR catch blocks all over the app and make our development process more scalable and once the provider is ready we'll tell refine that this is our data provider of choice that way refine calls the custom data fetch function automatically whenever we use one of the built-in hooks for doing any sort of data fetching or form submissions so let's start with this data provider a provider that is responsible for providing data to the entire application any queries or anything related to data fetching will be made within the data provider so to get started let's create a new folder within the source folder called providers and within it let's create a new folder called data and finally within data a file called index. TSX this is the place where we're going to set up this data Provider from scratch so we can first start by creating and exporting the client export const client this is going to be a graphql client to make requests to the graphql API so we can say is equal to new graph ql client which we need to import from refind Dev nestjs query and we can open it up right here by calling it and providing some additional options to it but before passing the options there is an additional parameter it is the API URL so we know which URL are we calling the data from so let's define it above export const API URL is equal to a string and now we can Define it like so https Colin api. cm. refine dodev and now we are referring to this API URL right here next we can expand this options object and we can define a fetch query this is going to be a callback function that accepts a URL of a type string options of a type request inid which is a built-in interface then we can provide the function block and we can open up a try and catch Block in the error we can simply return promise. reject error as error like that and in the try we'll try to make a successful request by saying return fetch wrapper to which we need to pass the URL as well as the options and now there are a couple of unknowns here where is this fetch wrapper coming from well that's something that I'm going to teach you how how to build so going right here to Providers and still within the data we want to create a new file called Fetch Das wrapper. TS and within it we want to create this custom fetch that is wrapped around the fetch that adds the authorization header so this is why we're creating it const custom fetch is equal to async where we have the URL of a type string and we also have options of of a type request in it and finally we have a function block creating a custom fetch is very useful for making requests to the graph Quil API improving code reusability because we can Define some specifics that are going to happen on every single fetch that we make in this case we want to add authorization headers so first let's try to get the access token from the local storage by saying const access token is equal to local storage. get item and then we're going to try to get the axiscore token next we want to get the headers from the options object by saying con headers is equal to options. headers and just so typescript doesn't complain we can say as record that's going to have a string and then another string so we're creating a type right here now that we have the headers and the access token we can return the fet request with the added authorization headers return await fetch that fetches the original URL that we pass to this custom function and then we pass additional options we spread all the options we pass to any request and then we also provide the headers inside of which we first spread all of the headers that we pass and then add this additional authorization header that's not going to be bare token by default it will be if we don't have anything else but for now what we can do here is get it straight from the Heathers by saying Heathers question mark dot authorization or we can do a bearer with the access token and we can also set the content type right here that's going to be content type of application Json now you know how often we experience those course issues cross origin request policy something like that right well to immediately avoid those we can can use something known as Apollo Apollo is a graphql client that we use in the front end to make requests to the graphql API so right after the content type we can say Apollo Das require Dash pre-flight and we're going to set it to a string of true there we go next we want to build a comprehensive error handling solution since we'll be working with a lot of data and we want to know if we're get the data back from our graphql queries so we can say const get graphql errors like so which is going to be a function once again this function is going to accept some params the first Pam is going to be a body which is of a type record which we can expand with errors and the second one is a graphql formatted error which is going to look something like this there we go and we can get an array of those or we can simply say undefined right here we can close it and now that we have all the parameters we need we can also Define what the function will output and that's going to be either an error or a null and then we can start defining the function block within it we can check if there is no body in that case we can return an object that has a message equal to unknown error and we can also add a status code of something like internal undor server uncore error now I can notice we have some warnings right here and I can notice that the graph Quil formated error is not yet imported so right at the top we can say import inside of curly braces graphql formatted error coming from graphql there we go now we want to do a second check if the body has errors so we can say if there is errors in body in that case we want to get the errors from the body by saying const errors is equal to body question mark. errors and then we want to join the errors into a single string by saying constant messages is equal to errors question mark. map where we get a single error and then we get its message by saying error question mark do message and then we want to call the jooin outside question mark. jooin right here like this this is going to turn all the error messages into one then we want to get the error code by saying const code is equal to errors question mark do zero question mark. extensions question mark. code and then we want to return an object that has the message equal to either the messages that we created or just the json. stringify of all the errors like so in case we cannot get the messages and then we can also do a status code of either code or let's do a 500 if we don't know which code it is now this error right here although it is an interface we don't really know what it contains and it doesn't include undefined it doesn't contain the message status code so let's create our own type of error right here at the top by saying type error is equal to an object where we have the message off string and we have a status code of string as well and now it should complain a bit less as you can see right here the only thing I'm missing is the double straight line right here and we are good finally if we have the body or if we don't have any errors we can simply return a null there we go now our function is happy and we can use it and fuse it with the custom fetch so right here below we can create a fetch wrapper con fetch wrapper is equal to an async function that accepts the URL of a type string and the options of a type request in it then we make the request using the custom fetch by saying cons response is equal to a wait we use the custom fetch function we have created pass the URL and the options and after we want to use a special function called response clone having a clone of the response is useful because once you've read the body of a response for example by calling response Jason you can't read it again because the response is consumed so if you want to process the response in multiple ways you need to clone the response first good to know right so we can do cons response clone is equal to response. clone there we go and now we can do something with it we can for example get the body by saying cost body is equal to a weit response clone. Json and then we can get the errors by saying const error is equal to we call our function get graphql errors and we pass in the body and finally if there is an error we simply throw it else we return the response so what we have done now is we have spent all of this time creating something that will help us a lot in the long run we have created our own custom fetch function you can think of it as middleware because it's going to be happening on top or before every single fetch we make and we have also upgraded it with the custom air handling function which now we have all in this nicely packaged fetch wrapper which we can export from this function close the file and finally be back where we're calling it for the first time so let's now import the fetch F wrapper from the/ Fetch rapper and as you can see we're calling this request and it's just so simple to call it you pass the URL on the options but the authorization is going to happen automatically and the airor handling will also be done now we also want to make something known as a web socket that's going to listen to subscriptions to this graphql API so whenever the changes happen we want to immediately listen to them now before we implement this websocket I want to tell you why we're doing this within the data provider in refine similar to the concept of data provider there is a built-in provider named live provider it allows your app to update in real time for example when a user adds something others can see it right away without refreshing the page similar to what we did in the data provider we'll create a websocket graph client using a library called graphql ws and provide the websocket URL it should listen to all of this we can then pass to refine and tell it to listen to changes in real time one thing we can keep in mind along with the configuration of the live provider is to activate live features in refine which we can do by turning on the live mode now let's get back to the code and we can do that by saying export const WS for websocket client is equal to and now we only want to do this if the type of window is not equal to a string of undefined so if we do have the access to the window meaning if we're on the web browser in that case we can open up theary operator and call a function called create client which will be coming from right here import create client and that's coming from graphql but this time DWS for websocket now within our create client we can pass an object of options where first we have to pass the URL which is going to be another variable we can create it's going to be called WS URL so we can say export const WS URL is equal to WSS col api. cm. refind dodev graphql so the refin team was kind of enough to expose both the API URL and the Ws URL for us so we can immediately use them we'll also need something known as a base URL by saying export const API base URL is equal to that's going to be htps col api. cm. refind dodev and now I believe we should have everything we need so we can pass the URL of this websocket client right right here as wsor URL and next we have to set up the connection params which is going to be a callback function where we get the access token const access token is equal to local storage. getet item accessor token like so and now that we have the access token we return it we return an object where we have the headers and within the headers we have the author ation with a bearer access token or at the end we can return undefined in case we're not within the browser so now we got the authorization handled as well as error handling so let me collapse this right here let me collapse the client as well and the last thing we want to do is create a data provider to make requests to the graph coil API so we can do that by saying export cons data provider is equal to graph graphql data provider inside of which we pass the client and this graphql data provider is coming directly from refine so let's import it right here at the top before the named Imports so right here graphql data provider it's a default export so we need to import it like this this is a function that takes a graph qu client and returns a data provider for refine to use and then we need to create a live provider to make subscriptions to the graphql API and similarly to create a live provider we need to create a variable and then call the graphql live provider inside of which we pass the Ws client which is our websocket client and of course we can import this right here from the nestjs query we can put it in a new line and we can say live provider as graphql live provider like so there we go and of course we can only call this if the Ws client actually exists if it's undefined we cannot call it so we need to add a Turner right here and say if WS client then call it else return undefined there we go so now we have both of these data providers which if you remember correctly we completely deleted before and now we're ready to come back and add them within the refin component which is the entry point of our refine application as you can see only a data provider is required to bootstrap the app and that's exactly what we have done right now so let's get to our data Provider by first exporting it from the providers we can do that by creating a new file within the providers called index.ts and within it we can say export everything from slata and now now we can import it right here at the top by deleting these previous Imports and saying import data provider as well as live provider coming from provids data or we don't even have to say data because we exported it from there and now we can use it right here that's going to be data and live provider we can delete both of these and then say data provider for the data provider and then here for the second one we can use the live provider great now save the file and go to localhost 5173 our app is working again after all this work but now at least fetching the data will be much much easier since we have complete error handling now there is one more provider that we have here that is left commented out which is the oth provider as the name suggests o provider takes care of letting users log in and control what they can do based on their permissions it manages things like redirecting users and handling errors we have the flexibility to integrate with any kind of third party authentication such as odd zero OCTA and others or Implement your own custom o methods if remember while setting up this project we choose custom option that's what we'll do now we'll create an OP provider object having all the necessary methods from login check which is responsible for checking if the user is authenticated or not login register error and even get identity which provides authenticated user information we'll create all these methods and call our graphql endpoint aka the data provider for complete foolproof authentication now let's see how we can do that in action now let's go ahead and develop our own o provider to implement the O provider we can create a new file within providers called o. TS and for this one specifically I've took the time to create it beforehand and provide a lot of comments along the way so that we can simply paste it and fully understand what it is doing so in the read me down below you'll be able to find complete O.S file it's about 150 lines but if you dive deeper into it you'll see that a lot of it are comments so now that we have it here let's look into it in detail together first we're importing the O bindings from refine Dev and then also the API URL and the data Provider from the/ dat then for demo purposes and to make it easier to test our app we can use the following Au credentials Michael Scott at dundermifflin.com and demo demo as the password next we create our OD Provider by creating a couple of different methods on it such as login log out on eror check and get identity login is pretty self-explanatory here we call the login mutation where the data provider. custom is used to make a custom request to the graphql API which will then call the data provider which will go through the fetch wrapper function I know a lot of providers and rappers already but we have to do this at the start because as the refund component says only a data provider is required to bootstrap the app once we have that you'll see how easy it is to continue so we're setting the off by calling the dataprovider that custom getting the data and doing a post request with the variables of email and doing a raw mutation to return the access token of that user then we set the access token to the local storage set the success flag to true and redirect to the homepage that is it for the login log out is also pretty self-explanatory its goal is to remove the access token from local storage next we have the on error which is additional error handling and finally we have the check which is used to get the identity of the user to know whether we're currently authenticated or not if we are we redirect to home else we redirect to login and finally we have the get identity which is used to get all of the information for that specific user here we return the information such as name email job title phone Avatar URL and everything else we might need about the currently authenticated user and that's it that's the entire OD provider now we can go right here to the index.ts of the providers and we can also export everything from sloth we can go back to our app. TSX and under o providers we can add our o provider coming from that/ providers and now our refund component is happy because it has everything it needs now the last thing we'll have to do before we start creating our routes is set up a workflow for typescript so that we don't have to write Types on our own for that we'll use graphql code gen allowing us to automatically generate types for everything in just a single command it's this one mpmi DD for development and then we add the graphql Coden CLI so let's copy it open up the terminal let's open up a new split window make sure that we're in there and then paste it it also requires additional Imports now that that is installed we'll also need some additional Imports down in the description or in the read me down below you'll be able to find a command that's going to allow us to install a couple more Dev related packages these packages include code gen typescript which allows us to generate base typescript operations which is is also a plugin for graphql code generator used to generate typings for operations such as queries mutations and subscriptions as well as graph kill Cen import types preset this one is used to optimize the way that types are imported in generated files these three packages work together to provide comprehensive type safety for our entire application with the help of graph quel schemas finally we also add preter and V TS config path this is used to allow us to create references to files when importing them such as coming from ad for/ SRC instead of typing do do dot do do Dot and so on this is coming out of the box with next GS but not with v so we have to add this additional package with that said let's simply press enter to install them and let's get ready to create our first routes let's add a couple of routes right here next to our welcome page this is where all of the routes in your refine application go so let's create a new route as a self-closing component say that it's going to be index and we can give it an element which is going to point to home in this case it's going to be a self-closing home component which we can import right at the top from pages so let's do it right here import home within curly braces coming from do/ pages but now if we go into the/ Pages there is nothing there so let's see what do we have we do have forgot password login and register but we're missing home so let's create it by following the example of how all of these other Pages have been created we can do that by creating a new folder called home and then we can create a new index. TSX right within it we can run just rafc to create a simple react error function component and we can call it home there we go now let's go ahead and Export all of these pages from the pages folder we can do that by creating a new file within the Pages directory called index. DS within it we can type export everything from slome and we can repeat this for all of the other pages that's going to be home but also forgot password after that we're going to have login and finally register what this allowed us to do is to now import all of these Pages within a single line home for God password login and register and thankfully these three pages have already been created for us by refine so now let's see why do I have an error here module. pages has no exported member home oh I know why that is the way we're exporting pages in refine if you check out for example forgot password you can see that it is export con something instead of export default which means that our page right here our home also has to be export const right here not necessarily export default which allows us to have multiple exports from a single file so now if we go back right here you can see that it's no longer complaining and tabs script knows that this is a jsx element now let's scroll down to where we have our routes and let's duplicate it three more times for our forgot password for our register as well as our login it kind of makes sense to have register first and then login and then forgot password index here simply means that we're showing it on the index page but these other ones will be showing on some other pages so we need to add a path to that specific route which in this case will be forward SL register then forward slash login and finally SL forgot-password if you want to we can explore these three pages and you can see there's simple pages that build on top of the refine Dev and design so we have our OD page with the type login where we pass some additional props and you can also go through it if you really want to see what this OD page is made of it can be a forgot update login and so on but in this case this has been abstracted for us by refine so we can focus on what matters which is building the business logic building the dashboards and not focusing on doing the same steps that we have to do in every single application such as building out O So now that we finally we have a couple of routes let's try to see how this looks like in the browser on our Local Host 5173 we have the welcome page that we've had before but now we should also have for SL login and there we go we have a beautiful login page built for us right out of the box we can also immediately navigate to sign up which points to SL register as well as going back to sign in and then even forgot password too now if we go to sign in we can see that some demo props have been passed in and we can try to sign in right now we have a 404 but don't worry we can start focusing on that right away I've put my browser side by side by our code editor so we can immediately see all of the changes that we make I'm going to zoom it out just a bit so we can see everything clearly and I hope the text is still visible if you want me to bump it up in the next video just let me know so now let's go into to login since that's what we want to fix instead of passing the demo initial values we can take the ones coming from our providers such as o credentials and we can automatically import these credentials coming from do/ providers we have created these before remember if we go to O you'll be able to see that here for demo purposes we're exporting these o credentials Michael scod and demo demo so now if we go back you can notice that we're using these now since the login is connected to our o credentials and our o credentials to our own o provider we are almost ready to start signing in but before that let's quickly visit our data provider which is defined right here under data provider command click it or control click it and let's make just one small change I noticed that both my API based URL and the API URL are exactly the same but the API URL should be the graphql endpoint of this base URL so we can instead write it like this we can make it a template string then use the variable of API base URL and then append the forward SLG graphql to it so now this is going to be our real graphql API Ino now if we have done it we can close all of the existing files and just keep R app. TSX opened or rather we are right now on login so let's see what happens if we try to login with our existing o credentials I'm going to click sign in and welcome aboard this means that we have been successfully redirected to our welcome page which means that the O is now fully functional not only that we are ready to get started with developing our homepage and by homepage I actually mean our whole app layout and the setup of authenticated and not authenticated routes if you think about it here we only have home as well as all of the OD routes but there are so many routes that our final application will have so let's go ahead and add them right away first we can start with the Heather component as it will be visible on all of the other pages so this is the first time that we're diving into the components folder which we first have to create so you can rightclick the source folder create a new folder called components and within the components folder we can have another folder called layout here we're going to keep all of the layout components such as the headers sidebars and more then create a new heather. TSX file within it and run our afce if this didn't work for you it must mean that you don't have the es7 plus react Redux react native Snippets extension installed so install it reload and then you'll be able to quickly create react components with that said rename it to uppercase Heather as it is a component after all and then let's get started with creating it now this header why do we need it well first we need to verify whether we have successfully signed our user in so we can do that by creating a new component within the header called current user so let's do that right away we're going to create a new special component within the layout folder called current Das user. TSX this is also going to be a react eror function component but of course it's not going to be named current Dash user is just current user now this component when clicked will return something known as a pop over so let's first wrap everything in an empty react fragment and then let's return a popover component right within it this popover is coming directly from ad D short for ad design also from ad design we can also get a button which is getting used to using ad design and if you're not familiar with ad design it's just ant. design on the internet and it's a UI kit similar to material UI or something like shat CN for Tailwind it has a lot of these components out of the box and it's exceptionally useful for dashboard like applications like the one we're building today so it's definitely a cool tool to learn and if you want to learn about a specific component we're using you can go to components and then you can search for it right here in the components overview let's go for pop over and you can see what a popover is you can click it and there we go when to use it is a simple popup to provide extra information or operations for example if you hover over this button you'll be able to see a pop over that is basically it the reason why I'm going over this with you is because I don't want to teach you just how to develop this specific application I want to teach you how to think for yourself and reading the documentation is one of the most important parts of being a developer so now we're using this pop over and you can even go a step further and expand the code and see how to use it that's exactly what we're going to do together right now you don't have to read it from here as I'm going to teach you but in case you want to do that you can so now let's figure out how to create this pop over pop over has a couple of props things like placement the title the content and more so let's start with the placement we can do that by defining a simple placement prop on it which is going to be equal to bottom right in our case we can also give it something like a trigger when will the popover open in this this case it's going to open on click then we can also do something like an overlay inner style this allows us to change the styling of specific parts of this pop over so we can say something like padding is zero and we can also add the overlay style which is going to be equal to and then we can increase the Z index to something like 999 to ensure that it appears on top and for now let's simply make this pop over return a word of test now if we go back and if we go back to Heather we can now use this current user right within our header current user coming from do/ current user and we can call it like a self-closing component now the question is how are we going to show this Heather on our page to do that we're going to make it a part of the layout why because we don't want to explicit recently mentioned the Heather on each and every page we just want to ensure that it's a part of all the pages so let's create the index file of all of our layout components by creating a new index. TSX within the layout folder there we can run rce again to get a simple react application which we can call layout make sure to export it that way as well layout right here now within here we can use some something known as a themed layout V2 yep it's a component called themed layout V2 and we can import it automatically from at refind Dev slant D the reason why we're importing it is because it's accepting a prop called header to which we can pass our header component which is coming from slhe header great now within this themed layout V2 we also need to pass our children as in everything or any page that is going to be there will show and it will be wrapped by our themed layout that's what the layout is for and then we can get the children of course as a part of the react props right here and since we're using typescript we can also Define the type for it such as react. props with children there we go alongside the header we can also provide a title so we can say title is equal to and we can make it a callback function where we automatically get title props as its first parameter there we can then return a themed title V2 which is going to be a self-closing component inside of which we're going to spread the title props and we're going to pass the text equal to we can do something like refine in this case or later on we can modify it to the name name of our dashboard and this is it for our layout so now let's figure out how we can use it now we can use this layout within the app. TSX by going right here below all of our off routes and creating a new route this one won't be self closing instead it will have an element prop equal to and then right here within it we can call the authenticated component coming from refine Dev core this abstracts the login functionality for us and it automatically tells us if we're authenticated or not so we can call it as a self-closing component and we of course have to import it and to it we can pass a key this key makes sure that this authenticated component is unique and we can do something like authenticated Das layout and foldback is very important here so what's going to happen if we're not logged in in this case the fullback will be the catch all navigate coming from refine react router V6 and we simply want to make that a self-closing component that will navigate to for SL login so now if we're not authenticated we simply go there but if we are authenticated then we can wrap everything in the layout component we created coming from do/ components SL layout and with this it we want to create a new component called Outlet now Outlet is not a component that we'll create rather it's a component coming directly from react router Dom it's a special component that renders the child route of the current route meaning that any route that is a child of the current route will be rendered inside of the outlet in this case the homepage is a child of the authenticated route so it will be rendered inside of the outlet and if remember correctly the layout is using the header so right here we should be able to see the header if we reload you can see that we have some issues right now even though we're on Local Host 5173 so if we open up the terminal we don't have any errors there and right here in the browser we can see that layout is not a route component all children of routes must be a route or react fragment interesting Let's see we have a layout and then we have Outlet uh and outlet has been imported from react rouer Dom and layout is coming from components layout hm why could that be well if I go here I can notice that we should have wrapped all of these components within the authenticated element and right now it's kind of being a self-closing element right here so just to better see this I'm going to put this on a new line and I won't immediately C close it rather I will make it a regular element and then now we have to put the layout within this authenticated so let's put it right here nested within it so keep in mind if we're not authenticated we fold back to catch all navigate to log in else we show a layout rendering all the children element and then we close the authenticated right here finally we're missing the close of the element so let's close it right here and then we need to close the actual route element as well and within the route we want to show the home so we can now delete this welcome page as we don't need it anymore and instead we can move this route index home into these routes right here or rather into the initial route where we have all of the other routes with the outlet and the layout so now if we save this you can see that now we have a test which is our header and then we have our home as well as the mobile sidebar if we click it this looks good right off the bat so now that we can actually see our layout why don't we go into it and then go into the header and now that we can visually see it let's turn it into a real header this is how that header will look like on the deployed application it's just a circular Avatar Photo and then once you click on it you can see a pop over or a popup that we have been talking about with your full name and a link pointing to account settings so let's create it and then automatically since we're using it in the layout it will be reused across all of these other Pages first we can go into the current user we have our pop over and instead of showing test we can show a real custom avatar so let's go ahead and create a new component within the components folder by creating a new file called custom - avatar. TSX keep in mind this is not in the layout just within the components folder run rafc to quickly spin up a new component and let's call it something like custom avatar but of course in Pascal case meaning that every first word is capitalized within here we're going to Simply use the ant D avatar so instead of a div we can use the ant D avatar like this which we can import from ad design by saying import instead of curly braces Avatar as and the avatar coming from Ant D and then within it we can put the name initials of this person in this case I'm going to do JM for JavaScript Mastery now why does our header still say test well that's because we haven't yet used this custom avar component within it so here we can use a custom avatar which we can import from d/ custom- Avatar and call it as a self-closing component and there we go you can immediately see this JM on top left now let's style it a bit let's give it a couple of props such as the alt tag of the actual name of this person and all of these properties will be coming through props but for now let's simply call it John do or since we use JavaScript Mastery we can use JavaScript Mastery here as well next let's also provide the size equal to small and let's provide some additional styling style is equal to and we can provide a background color so let's do background color of let's do this Coler that chat GPT automatically recommends 87d 068 there we go we have to properly close it and save it there we go that's looking good to me now alongside the back background color we can also give it some additional properties in this case we can give it display equal to flex we can also give it the Align items equal to Center and we can give it a border equal to none now it's possible that we're going to pass some additional props or some additional Styles as props to this custom avatar component so let's immediately grab them right here through props we can destructure them and get a name we can also get style and we can spread the rest of the props like so and we can add type of props in this case we can Define this type props equal to Avatar props which are going to be coming from Ant D and we can add our own which is going to be name of type string there we go now we have our props and we can actually use a real name which we can pass through props so now we're calling it but let's go ahead and pass it as well into this custom avatar component to be able to pass these things for the first time ever we're going to use our OD provider or rather a function we have created in there use get identity so we can say const data which we can rename as user is equal to use get identity coming from refind Dev core what this Hook is doing is it's actually getting our own function that we created and hooked up to our o and we can see that if we go to our o provider there we go we have our get identity which gets the user information and what this refine core hook does it simply allows us to use it and provides everything we requested or specified right here so now we know exactly what we're going to come back not only that we know what we're going to get back but typescript also know which is the beauty of refine and graphql uh so let's define the type right here as user we can do it within these kinds of brackets and this user will be coming from graphql schemas so this is the first time that we're using a graphql schema so let's import it at the top import type user is coming from at SLG graphql SL schema. types now this is the first time that we're using the reference to a specific path using the ad forward slash and I don't think we have fully set it up yet even though we have installed the packages needed to run it so what we can do to make it work is we can go to our V.C config.sys paths like so and then we can add it as the first plugin right here by calling it like a function on top of that we also have to open the TS config.js right at the end after jsx we also need to add a comma and then say base URL is going to be dot a string of slsrc so we know that everything is starting from the source and then we can also add pads and those paths are going to look like this it's an object inside of which we have ADD forward slash and then asterisk which means everything and then we can make this an array of Slash everything so this is simply a way for us to let the TS config know how we want to refer to specific files without saying D Slash Da slash. slash and moving all the way to the source so this is now good and if we go back we should now be able to use this graph quill schema we should now be able to refer to this file directly through references let's just reload the terminal just to be sure by running mpm runev one more time and reload it and it does seem like your page is active right here we don't have any errors but we do have one error if we hover over the graph Quil schema types it says that it cannot find that module that's because if you try to control or command click this file you'll notice that it doesn't actually exist we haven't yet generated it we haven't written the types manually nor we have created a system that would automate creating the types for US based off of graph fuel schemas so first let's set up a graph kill config and then we're going to tell it how to create those types we can do that by creating a new file in the root of our directory called graphql do config .ts in the read me down below you'll be able to find a full graphql config so simply copy it and paste it right here there's a lot of comments I really try to do my best to explain everything that is happening here but still let's go through that together first we specify a config which we import from graphel config this is just the type for the config itself we have to define the graph coill schema provided by refine and then we add a couple of extensions and then the most important one here is code genen which is a plugin that generates typescript types from graphql schemas for us automatically we can also add a couple of hooks which are being executed after a specific action and then we want to say what do we generate and here you can see the reference of the file we were trying to use within our current user the graph schema types which are going to be generated really soon and then we add the preset the documents this is mostly template that we're following with every single graph kill config now that we have this we also have to modify our package.json file by adding an additional script so let's navigate over to packet Json and by the way to open this little window which is very useful you just press controll or command p and then you're able to start typing the name of the file you want to go to and simply press enter and it's much quicker than opening up the Explorer once you're here we can go to the scripts part of our package ason there we can add a new script called code gen like this and it's going to call a command graphql Dash code gen there we go so believe it or not code gen will automatically generate all of the types for us it's kind of like having all of the benefits of typescript without it doing all of the dirty work which is actually writing typescript types and interfaces cool right so let's see how we can put this into action we can open up our terminal and while keeping the first one running we can now run mpm run code gen and press enter you can see it's going to run graph quill Coden and it will parse configurations and generate outputs it looks like it loaded the graph quel schemas correctly but it was unable to find any graphql source files the reason we got this error is because we haven't yet created any graphql mutations or queries so let's create a new folder in the root of our directory called graphql and let's create a new file called mutations. TS as well as queries. TS now throughout our entire application we're going to have a lot of queries and a lot of mutations working with a lot of different pieces of data these queries are very specific they go through sorting pagination filtering and just contain a lot of stuff to write but aren't very complicated to understand so what I would like to do in this video is provide you with a complete queries. TS file which you can find in the read me down below copy it and then paste it right here don't be scared I see that it is 250 lines long but once we visit a specific part of the application that uses one of these queries we're going to come back to it and then I'm going to explain in detail how does it work for example this dashboard total counts query which queries the dashboard total counts and Returns the total count for companies contacts and deal I'm going to explain every single one of these queries once we actually use them within the application now let's repeat the same thing for mutations as well you'll be able to find full mutations which you can copy and then paste right here we're going to come back to this later now that we have both of our mutations queries as well as the graph K config we are able to rerun this command which will automatically generate all of the types for us but before I do that there's one small thing I want to tell you and that is that there's a special graphql extension right here which provides syntax highlighting for graph Quil files so if you install it and then go to something like queries and nothing because it's still a template string I think I think we might need another graphql LSP extension so graphql language support let's install it it must have 1.8 million downloads for a reason right and now that we do this you can see that it's no longer a string even though it is within a template string but this extension really nicely reads the query as well as all of the objects and filtering functions and everything else within the query itself so this is now very good and it's going to help us later on but with that said let's open up the terminal and let's run the mpm Run Coden command and still we have the same error let's try to debug it uh it says unable to find any graphql files in Source something and then TS files if you look into our queries it indeed is a TS file but it's with the graph Quil folder which is not within the source and it's specifically looking for graph Quil files within the source so we simply have to move this graph Cod folder within the source folder there we go I always like to include this little bugs because you could spend hours debugging them and they happen to everybody but it's just a matter of how you're going to approach actually solving them so now that we have done this um I can try to rerun this command for hope y third and last time there we go pars configurations and generate outputs now if we go back to this same graph quill folder we can see two additional things have been created for us schema. types. TS which looks like some witchcraft right here uh typescript witchcraft uh but we do have something here we have a lot of different things that we might want to use across our application uh for for all of our objects and for all of our documents we'll be using companies yeah it's really anything uh and all of this has been generated for us automatically by code gen since we're using graphql and since we're using typescript we also have a bit of a simpler to understand file which is the types. DS and here we have any types that we might want to use for example type for the update company mutation where we know exactly what we want for a specific company we also have I believe the user so if we search for user we can search for a capital user like so and if we scroll a bit here we should be able to find our user type no it doesn't seem to be here but if we go into the schema types and search for user here there we go we have created by user and there we go we have our export type user which has all of the properties we might ever need on the user object so going all the way back to where we were keep in mind I know this is taking a lot of time but we're doing the groundwork we're doing the setup for the project which is going to significantly help us in future development of this application keep in mind all of this started since we imported this add/ graph schema types first we had to fix our references to specific files and then we had to actually import the user type which now that I think about it I was searching for it all across those files but typescript is so wonderful because now we can immediately hover over it and we can see exactly which properties does this user have not even that we can try using this user by saying user.name and it automatically knows what this user property has we can also search for something like there we go take a look at this this reminds me of my University days in computer science when I was using Java Java had such a wonderful intelligence system and it let you know everything all the methods all the properties that is specific object has and this is exactly how it feels like I can literally see what my user object has and heck it even adds a question mark for me because it knows that the ID could potentially be undefined and if I type something like something right here it's going to let me know no something definitely doesn't exist on the type user so it took us some time but trust me it's more than worth it and it's going to save us from making so many mistakes in the future so all of this started by trying to provide additional props to this custom avatar which we now can do by going right here and then giving it a name prop of user question mark. name or even if I type name I think it automatically does it there we go we also can provide a source which is the profile photo which is the avatar URL and then we can also provide the size of default and a style of cursor Das pointer now we're providing these properties we can go into the custom avatar we can say that the name is optional because sometimes it's not going to be there we can spread all of the existing Styles right here daada do style in case we want to make some modifications and we can also spread the rest of the properties outside the Styles right here by using this syntax now we have the actual profile photo because it applies the Avatar URL we can also use the name here in the alt and you cannot see it right now but if we don't have the profile photo then we need some name initials because JavaScript Master is definitely way too much to fit this so we can develop a custom get initials function to create this utility function we can first create a new folder called utils often known as utility functions or simply said functions that we can reuse across our entire application just helper functions since we'll have quite a few throughout the entire build of this application and since mostly the utility functions are now being created by Chad GPT because they're just so generic which means that Chad GPT can generate it I generated a couple of these using Chad GPT and I provided them to you right in the description Down Below in that same read me file you'll find a z zipped utilities folder download it unzip it and then paste it right here within the source folder it's going to look something like this utilities where we have some date utilities currency numbers get name initials get random colors stuff like that right but specifically we're working with the get initials now which simply takes a name splits it Maps over it and then you end up having just not JavaScript Mastery but let's see what do you get if we go here and we call get name initials now we can see how this automatically works I just press control space and it recommended me the reference to this import add for/ utilities and we can pass our name and it's complaining a bit here saying that the name possibly is not a string so we can also here say or an empty string there we go now if I save it you can see Ms for Mastery as in JavaScript Mastery that's great and why did I mention Chad gbt because nowadays this is basically the one thing that it's phenomenally good at you can basically create a comment saying something like create a function that gets initials from a name and then you can use GitHub copilot and it's going to do it for you right here or you can use chat GPT and then just Bas the function it's perfect for these simple use cases but trust me it's not going to replace you as a developer for a couple of decades so I don't want to see those comments is AI replacing all of us soon no it's not but it's just there to help you and there we go now we have the get initials but I will also bring back this rest operator because now we have a photo there we go not looking good so far but it will look better soon now that we have this custom avatar let's get back to the current user and let's figure out what happens once we click on this custom avatar we have to create the content for the pop over to do the content for the pop over we can create a new variable con content is equal to and it's just going to be a div yes you can Define elements like this and then use them within your jsx later on and we can give this div a style property of display is equal to flex as well as Flex direction is equal to column we're using CSS injs right here within this div we're going to use a text component so let's first create it we can create it within the components folder it's going to be called text. TSX and this text is exactly what it says to be text so in the read me down below you can find the text. TSX component copy it and then paste it right here you can see that it seems like it has a lot of lines but basically we're defining different sizes right here so we're making our app extensible for future use whenever you want to have small or extra small or extra large text this automatically applies different font sizes and line Heights to it so it's just so much easier to use now if we close that and go back we can now use this text element which is coming from do/ text and to it we can pass a couple of props we can pass a prop of strong as well as additional sty properties of padding 12 pixels on top and bottom and 20 pixels on left and right within it we can render the user's name so user question mark. name then we can go a bit below the text and create a new div element within this div we're going to render a button and that button is going to have a style property of text align which is going to be set to left it's also going to have an icon which is going to be equal to setting outlined icon coming from add design icons we can self close it right here it's going to have a type of text as well as a block property and on click we want to modify one of the states in our application it's going to be a state of set is open um and then we're going to Simply set it to True right here of course this state doesn't yet exist so we can add it right here at the top by using the use State snippet is open and set is open there we go like this and we need to import Ed State coming from react and at the start it's going to be set to false so now we're setting it to open and this button will therefore say something like account settings so this is going to open up a completely new model so let's see if we click it nothing happens yet because we're never using this content right so what we can do is we can now use this content and add it as a prop to the pop over content is equal to content we have just created so now once you click on it you can see Michael Scott and you can see account settings we can also provide some additional styling for this div wrapping the button we can give it a style equal to border top of one pixel solid #d9 D9 D9 we can also give it some padding of four pixels let's give it a display of flex as well we can give it a flex Direction so that it shows in a colum and a gap of about four pixels to make some space there we go that's a bit better so now we have this account settings you can open it you can close it as well that is our pop over and then here we're going to have some account settings right now we're never looking into this is open so let's actually put it to use right here below our popover we can then display a new component depending on the open state but we only want to do it if we have a currently logged in user so we can say user and end a component called account settings there we go it's going to be a self-closing account settings model we can even display it like this so it's a bit easier to see what's happening there we go now let me show you how this account settings model looks like if I click on it here in our deployed application it just pulls this model right here where you have a photo you have a name email job title and a phone number and you can save it if you want to this is all it is so let's go to our components layout and create a new file called account- settings. TSX and in the same read me you found all of the other code you'll also be able to find the complete account settings component simply copy it and paste it the reason why I wanted you to copy and paste it is because it's a lot of jsx uh we're using a drawer component here and some cards with forms but essentially it's just a couple of inputs and a photo and a save button that's it and all of the refine actions here have been very heavily documented so you can see exactly how we're doing the update action that's it you can see we're also using the custom avatar from here but it doesn't seem to be imported from the correct path so I think we used it as a default export so here we can remove those two and now it's looking good great and now you can notice that we need to pass three different props to the account settings opened set opened and user ID so let's do that opened is going to be equal to R is open set opened is going to be equal to our set is open and then finally we pass the user right here and then we import account settings from account settings you can press control space to automatically get this import it's complaining a bit about the user saying that it's not assignable right here and that's because we don't need to pass the entire user just the user ID so if we say user ID is equal to user. ID we should be good once again typescript save us right here so now if I click on the account Avatar and then account settings we have this nice looking drawer that comes from the right side of the screen on desktop devices it's going to look something like this looks great as well now let's finalize our header because this is not looking good it's just stuck in the top left corner of the screen this is how it should look like so let's close our current user and finally now that our current user is completely done we can focus on finalizing the header component the header is going to use a couple of components from ad design we're going to wrap everything with a layout. header component and this layout is coming from ATD so we can automatically import it then we wrap the current user but we also want to provide it some space so we can use a space component also coming from antd and then put the current user right within it this space can have a property of a line is equal to Center and size is equal to middle and to the header we need to provide some custom styling so let's say style is equal to header Styles and then we can Define them right here const header Styles is equal to and we can define a background color to start with such as FFF and that's good there we go it's actually white now we can give it a display equal to flex to make it a flex container we can give it a justifi content of flex Dash end to move it at the end of the screen we can give it a line items of Center so now it's vertically centered we can also give it some padding like zero on top and bottom and 24 on left and right we can give it a position equal to Sticky so it's actually going to stick to the top we can give it top zero then so it knows where to stick and a zindex of 999 now this style is going to complain that it's not really a style so we have to let it know that this object indeed does contain the Styles so we can Define the type of react do CSS properties and we can save it right here there we go so now it's looking good it doesn't complain and we have our header inside of which we have our account and then account settings right here finally the header is done and we cannot see the home but yeah we are on the home right here you can see it just barely behind this sidebar thingy so now we have the homepage this is the home we're seeing and we can focus on adding some of the other routes as well later on we're going to have companies tasks and log out but for now let's just focus on adding all of these links to our sidebar and then we can nicely navigate between them and to do that in refine we have a special resources config file that we have to create so let's go to our source and then create a new folder called config and then within config create a new file called resources. TSX inside of here we can export const resources which is going to be of a type I resource item which is coming from refine Dev core and we want to have an array of these right here which is going to be an array now these resources are going to be path definitions that are going to help refine recognize the available actions for all of our resources at specific paths there is a great documentation page on refine that it explains this in a more detailed way but in short actions are basically the paths that you can use to perform crud operations on a specific resource it's like grouping the crow operations under a single name so it's going to look something like this I'm going to add this comment right here a resource in refine performs these actions list which gets all records or reads show which gets a single record also read and then create edit and delete or clone so let me show you how that would look like first we can create an object within this array with a name of dashboard then we can also add a list right here which is going to be just forward slash we can also provide something known as a meta which is used to store any additional information about the resource anything you want in this case we can put it as an object with a label with a dashboard of uppercase D and we can also give it an icon which is going to be a self-closing dashboard outlined icon which we can automatically import from ad design icons and now we can provide commas as well to nicely clo and let's not forget to close it there we go so this is our first resource so now the question is where are we going to make use of these resources let's go to app. TSX as that is where our primary refin wrapper is right below the the O provider we can provide resources is equal to and then we pass the same resources which we import from config resources in the context of crow applications a resource typically refers to a data entity that can be created read updated or deleted and in this case dashboard is one of these and it automatically shows it the dashboard in this case is our home but now if we go further into resources it's going to start making more sense because the second resource is going to be companies so let's go right here create a new object with a name of companies with a list of forward SL companies as well show and here you can provide the route to show and do you know what a show is show is to show a specific company just a single document so that's company's ID we can also create so the route for create which is companies let's do new in this case and we can also do edit which is going to be company's ID or edit or in this case I think it's better to do edit and then for Slash the ID which we want to edit we can also provide the additional meta information such as the label of capitalized companies and then we can do something like shop outlined and we can import this icon from add design icons and we can duplicate this object one more time below and we can do everything the same but this time for the tasks so we can say tasks forward slash tasks show task ID we won't have the show as we'll only be showing multiple tasks create which is going to be tasks new tasks edit and then meta which is going to be tasks and we can also provide the icon of project outlined which we can import right here from add design icons and now we have all of our resources which we're importing in using within this refine wrapper and you can see how immediately they are now showing up right here on our sidebar as well and the routing has been automatically created for us too and if we go to companies or tasks right now you can see that we will be redirected but nothing will be shown on the screen that's because we of course haven't yet created a route for that specific path or created a page that will be shown on there for that matter so we'll do that soon but the routing works and soon enough all of our pages are going to look like this we're going to have companies which is going to be a complete dashboard of all of the companies of course it looks much better on larger devices where we have a completely responsive dashboard design where you can search by specific company titles we also have the actions such as edit that opens up this complete form and then you can also see the contacts belonging to that specific company and you can of course delete them and let's not forget to create there we we go then there's also the tasks which is a complete can band board which we're going to also develop from scratch where you can add new cards and then you can also add card details which is very similar to something like Trello or even jira there we go and you can of course drag and drop and move everything in real time so exciting stuff begins now first we're going to start with this dashboard that looks amazing on Old device but dashboards definitely shine on desktop sizes we're going to have first of all these top cards to show some highlighted information then the upcoming events deals section and then the latest activities so with that said let's turn this home or just e at the end into something more like this to get started with the homepage we can navigate to the Home Route which is Source Pages home and then index.ts X where for now we simply say just home our homepage is going to be wrapped in a div but then immediately after we want to use an add design property called row which we can again import from add design it's not a self-closing property because we need to pass some columns into that row so let's provide our first call which is also coming from ad design so you can automatically imported and inside of there we can show our first component which is going to be our calendar upcoming events there we go so now we can see it here and then below this column we're going to show another one but before we duplicate it let's provide a couple of props to it first such as on extra small devices it's going to take 24 spaces on small it's also going to take 24 on extra large is going to take eight and we can also give it a style of height is is 460 pixels in this case this is just the total number of rows and what this 24 means is just a total number of columns per row so here it's going to take the full screen here it's going to take about oneir of the screen great now we can duplicate this column entirely and the second one is going to render the dashboard deals chart so these are two different components which we're going to create soon and this this one is also going to have all of the same properties now let's also provide some of the props to this row such as a gutter property of an array of 32 and 32 this is going to provide some spacing as well as a style equal to margin top of 32 pixels so now we pushed it a bit and we can see how these rows or columns are working on mobile they're showing one after another and then if I expand it a bit you can see then they start showing one next to another so this functions well and now we can actually Implement these two components so let's go to components we can create a new folder within it called home because we're going to put specifically the components for the homepage right here and then we can call this component upcoming Das events. TSX and there we can run our rafc whenever you run our afce automatically switch this to Pascal case upcoming events there we go and let's also implement the second one which is going to be the deals chart so new deals- chart. DSX rafc and then modify it to Deals chart now we can import these two components right within our index and to import them here we first have to export them within the components so let's create a new index.ts file within the components folder inside of here we can import these two new components we have created um so that's going to be import upcoming events from home upcoming events and we can also have import deals chart from deals chart and then we can export them like this export an object containing those now if we go back we can simply import upcoming events there we go from add/ components as a self-closing component and then the other one is let's just see what it was if we go here and to the index it was deals chart so if we go back we can now do deals chart and get it from components as well that one index file allowed us to get all of these in a single import and now we have upcoming events and Deals chart which means that we can now controll or command click into the first one which is the upcoming events and we can start developing it let's first start with the jsx part which are going to be this single card that's going to show us all of the upcoming events such as this annual company picnic or cross Department collaboration meeting I'm sure Michael Scott has quite a few of those so let's start implementing it first we want to wrap everything a card and that is of course an andesign card so we can immediately import it if we save it that immediately gets turned into a card we can also give it a style property of height is set to 100% there we go so now it fills out the space and we can also give it something known as a head style where we can provide some additional padding of 8 pixels on top and bottom and then 16 pixels on left and right alongside the head Style we can also provide something known as a body style this style right here allows us to also provide a padding to the body so we can do zero on top and bottom and one REM on left and right then we can also provide a title but this is getting a bit messy so let's position or indent all of these props into new lines and then the next prop for our card will be a title we can say something like upcoming events and then it gets displayed on the top so we don't need upcoming events within the card anymore because that's going to be the card body but in this case we're going to style the title a bit more we're going to turn it into a complete jsx component we're going to wrap it into a div and that div is going to have a style equal to display is set to flex align items is set to Center and then also Gap is set to eight pixels to give it some spacing within this div we want to have an icon of calendar outlined which is coming from add design icons to automatically imported I just press enter and then we also want to use our own text component once again I'm going to just press enter on the do do/ text to import it and we can simply say upcoming events right within that text of course we can ALS Al give it some props such as size is equal to SM for small and style give it a margin left of 0.7 RAM and of course this has to be in a string because we're doing CSS and JS makes you appreciate the nice utility classes of tailwind and right here we have our upcoming events and this is looking very nice we have a card title now the question is what are we going to show Within in this card so first we can also create a loading State because first before we show the data we'll be loading that data so let's create a new used State field or used State snippet called is loading set is loading at the start let's set it to true so we can test out the loading State and let's automatically import used state from react now we can open up a new Turner block and say if is loading or rather is loaning in that question mark in that case we want to show a list this is a special component which we can import from and design or just and D we can expand that list for now and then say colon or meaning what's going to happen if we have loaded the elements and then we can also render a list there we go by default the list will say no data so let's try to show at least something on this first list we can add add a prop of item layout which is going to be set to horizontal we can then give it a data source and usually you would pass real data coming from the database or an API but here we can just demo or mock specific data by using the array Constructor or saying array. from length is going to be set to five we can then map over it by using the dot map where we get the index of a specific property it's the second parameter so we use just an underscore to signify that we don't need the first one just the second one and then we simply automatically return an index within an object to automatically return you have to wrap the output inside of parenthesis so first parentheses and then an object usually it will just be a function block where the ID is set to index so we're essentially mocking a couple of elements to show right here and I don't think I'm closing it properly we need one more parentheses there we go so now it's kind of like showing something but nothing is there yet and while we're rendering the items we might want to show some loading States or also sometimes known as skeletons I'm sure you've seen them everywhere on the web here are a couple of examples I believe this one is for LinkedIn and this is a mobile version medium Facebook when you don't have the data or when the connection is not as good you want to show something to the user and that something is in most cases just a gray rectangle that slowly pulsating saying that something is going to come here and fill that space out so let's create this skeleton and we're going to have skeletons for all different kinds of components in our application so first let's create the skeleton for the upcoming events this skeleton is going to be within our components so that's right here and then we can create a a new folder called skeleton within that skeleton we can create a new file called upcoming D events. TSX and the skeleton is basically nothing else than a simple react component here is how it looks like you basically render what you usually would but then and design provides a special component called skeleton which you basically just put where you would usually put your content in this case as a button within the list item and then it shows those gray rectangles now since we're going to have a couple of these skeletons and since you wouldn't really learn anything by me having you to type them out I'm going to provide you the full folder of these skeletons so delete the folder you have created right now and just find the zipped skeletons folder Below download it unzip it and paste it right here within your components folder as you can see we have a couple and one of these is upcoming events before we use these skeletons we also have to export them so in our index.ts file we can quickly do that by simply importing and then exporting some of these components that's going to be upcoming events but I think we should call it a skeleton right here yep upcoming events skeleton so we can say upcoming events skeleton and unfortunately it doesn't give me the Auto Import so we can do it manually by saying import upcoming event skeleton from skeleton SL upcoming events skeleton no that's not it I think we just called it upcoming events because we have the folder right here indicating that it's a skeleton there we go that's good and we also need to repeat this for the four other ones let's see which other ones do we have as well that's going to be the accordion header so let's import accordion header skeleton there there we go now it's doing a bit better let's also import something like a can Ben column skeleton that's better and let's also import the project card skeleton there we go and I do believe that's it we have 1 two 3 four now we're missing one we have the latest activities so let's import latest activity skeleton and now we can just in new lines put all of these new skeletons let's do just that there we go we can even divide them with one empty line and then say upcoming events accordion header canand column project card and then latest activities skeleton and what this now allows us to do is go back to where we were in the upcoming events and then here we can provide an additional prop called render item where we can have a callback function that's going to render the upcoming events skeleton and now we do get get this automatic import from the skeleton folder there we go and we can just self close it now if we do this we need to provide something in the list as well or in this case we don't we can just self close it and of course I have to close the surrender item as well so now you can see how nicely it's loading for our five imaginary data source items 1 2 3 4 5 and we can see this nice animating skeletons but as soon as I I switch this is loading to false which is how it should be there's no data because now it's our job to do the second list the list that happens once we actually have the data so some of these things are going to be similar first of all of course the item layout item layout is also going to be horizontal we don't want to change that the data source is going to be completely different because now we actually want to fetch real data so for now I'm just going to Simply put it as an Mt array but soon enough we're going to provide some real data sources and we can also provide the render item which means for each one of these array items what are we going to show or render so let's get the item itself and then in the Callback function we can open up a new function block and then just return something in this case for each one for each item we want to return a list. item all uppercase like this and this list we have already imported from antd within this list item we also want to render a list. item. meta which is going to be a self-closing component to which we can provide a couple of props we can provide the Avatar which is going to render some kind of a badge with a specific color so in this case we can render a badge element which we can import from and d and it's going to have a color equal to item. Coler so we're going to get it directly from this item we're trying to render now our typescript is complaining because we don't have a Coler on an empty array or on nothing that's within the array but soon enough we're going to fetch real data sources for our upcoming events so we'll be able to display something before that let's just finalize what we want to see within each list item we definitely want to have some kind of a title which we can wrap within our text container or our text component so let's just wrap it text and let's give it a size equal to XS for extra small and let's just render the render date and within it let's try to render the date of when this event is happening usually dates are just in plain JavaScript objects so we have to actually render it in a human readable format to do that we can do it right here at the top by saying const render date is equal to get date which is a utility helper function which we can import and to it we can pass the item do start date as well as the item. end date and it's automatically going to generate it in a human readable format again for now just ignore these tab script warnings as soon as we get the real data it's going to exist on the item so it will render it properly and now within the title we can simply render the render date below the title we can also render the description which is going to be yet another text element and this text is going to have an ellipsis property ellipses is those three dots when the text is too long to fit in the container and we want to turn on the tool tip to be true so once we hover over it we'll be able to see the full thing and we also want to make it strong so we can give it a strong prop it's just the Bolder text and there we can render the item. tile I believe this is it this is everything we want to render within our list item now if we save it once again nothing is happening and that's because we're not yet fetching any data which is exactly what we're going to do now we have to figure out how we can populate this data source and boy that's refine make it easy now we'll finally start making use of all of the ground work we've done we've laid out the foundations which now allow us to use all of those resources remember the config or the resources we've created right here one of these was tasks companies and dashboard now we'll be able to just consume some of these resources and just make cred operations on them specifically here for the config we listed the ones that we want to show on the sidebar such as companies tasks and so on but in this case we'll be using the resource of events so let me show you how we can get access to all of the these events and then display them right here at the top of our upcoming events we can say const and then destructure the data and the is loading state which we can rename to events loading and that's going to be equal to a cook call of use list which is coming from refine Dev core it's a function it's a hook specifically and we have to pass an object to it inside of which we Define which list do we want to use and exactly what kind of data do we want to get back let me show you how it works here you can say resource and you can provide the name of the resource you want to fetch in this case we want to get events there we go now if we save this let's try to see what happens now as you can see this temporarily broke our app but that's good and I'm happy that it did it gave us some time to fully figure out what exactly used list is and just how powerful it is used list is a hook created by refine that allows you to fetch data from your API within their docs we can see that it is an extended version of the tan Stacks queries used query that supports all of its features and then adds some more when you need to fetch data you can do it automatically you can do sorting filtering pagination everything from a specific resource it uses the get list method as query function from the data provider which is passed to the refin component it also caches the data and does a lot of exciting stuff as well and here's an example of how we can use it similarly to what we have done right now you simply get the data the loading the error and Define the resource but in our case we're using graphql and we have to add a specific graphql query as a meta field to this use list hook so let's add it right here meta which is going to be an object where we can provide the gql query in this case because we're doing a Fetch and here we can do dashboard all uppercase dashboard calendar uncore upcoming events query which we can automatically import from queries now if we get back everything seems to be working no more errors now we're providing the US list everything that it needs but as I promised let's now dive into this gql query and look exactly what it does this one is of a medium size we're doing a query on the upcoming events and we're also passing some variables in graphql you can pass some variables such as filters sorting and paging and then we can use those to filter out the documents we want to get back so here we're saying give me the events but apply a filter apply sorting apply paging return the total count as well as all the nodes and then the nodes which are the actual events May contain these fields we just pass this gql query here in meta we Define the resource as events in the use list will'll do the rest let's see if we're immediately getting something back within the data so I'm going to console.log data or just so we don't have to open up the console let me just alert that so I'm going to write alert start and then pass the data right here or maybe Json that stringify data that's going to be better and there we go you can see it right here we get back the data with the ID title Coler start date end date and that's it and we get many of these events back which means that this is working we have a fully functional mock database that was created for us by refine that allows us to test this dashboard and of course this might as well be your own fully functional database that you will create it can be an SQL or non-sql database you can use Prisma you can also use mongus the thing is refin Hooks and functionalities allow you to very easily consume all that data within your application with the concepts of resources and lists so you simply Define the resource you can Define The Meta version in this case of how you're fetching it using graphql from the database and then you simply get it back that that's it but now if we're getting back to data why does it still say no data well if you remember we didn't yet properly pass it over to the list so here in the data source we can now say data question mark. dat or simply an empty array if nothing is there if we now save it you can see all of these events get populated right here but hey we have just a few too many they jump out of the card so let's figure out how to do some filter string or maybe even better pagination yep you can Implement pagination with just a single line pagination page size is going to be set to something like five and you save it automatically refines used list hook will recall this gql query to which we're now passing the updated page size which is going to implement pagination on our resources this is the power of refine and using graphql as well as typescript to provide comprehensive and scalable environment for developing medium to large applications this is where refine really shines now that we're nicely getting these elements let me also show you how to sort them by start date we can do sorters and then we can also do an array and then provide a specific sort such as field is the start date date and order is ascending so if we do that they're going to be sorted by start date we can also apply some filters which is going to be an array of filters and in this case let's say we want to filter by field which is start date and we can apply an operator which is going to be GTE uh it's not a game GTA no it's going to be greater than that's what it is and then we can also apply a value which is going to be a specific date but in this case we can make use of the DJs Library so we can say DJs and call it as a function and then use the dot format where you can provide your specific date format in this case it's going to be y y y y y mm and then DD and of course DJs is a package which we have to install it's a fast 2 kilobyte alternative to momentjs with the same modern API you just call it and you get some date functionalities so so to get started you first have to of course install it by running mpm install DJs so I'm going to open up our terminal split it up and then simply run mpm install DJs and in a moment it should automatically be installed and then we can import it from DJs so now we're getting the elements as well as applying pagination sorting and filtering it is as easy as that now let's go right here below we have a list right and we can also figure out what happens if we finish the loading but we don't have any elements to show we can do that right here below The Return by opening a new block and say if not is loading and data question mark dot data. length is equal to zero then we can show a new block of code it's simply going to be a span that's going to say no upcoming event events and we can also apply some Styles such as style display of flex we can also give it a justifi content of Center align items of Center and a height of about let's do 220 pixels so it's nicely centered and let's see why is it complaining right here we're properly closing it we're closing it right here yeah this is looking good but apparently we're not not closing something else up oh yeah I think this should go right here below not within the list because this is not a list item it should go above the card right here there we go of course we won't be able to see it now but if the data was empty we should be able to see it also there's nothing in the list so we can simply self close it because it's getting the data and rendering the list items and believe it or not that is it and and if I scroll up I can see that I'm only using the is loading but not set is loading and that's because I thought that I need to have my own state but with refin used list you don't even have to create your own state it automatically exposes the is loading and error properties so you can immediately use them out of the box and you don't have to modify them and change them later on refin use list does it for you and there we go believe it or not that is it for the upcoming event we have not only created this component but for the first time ever we have consumed the data from this mock database that was provided for us by refine and we were able to play with it and test it out this is how it looks like on larger devices it takes just onethird of the screen I think and still looks great of course this was only quering no full crowd operations yet but we're going to see that very soon for now the most important part for me is that you understood how we can use the useless tuck to get a specific resource in this case events and automatically apply pagination sorting and filtering and most importantly how we're utilizing the meta property to apply a specific gql query graphql query to this used list so it knows exactly what it has to fetch in this case the upcoming events great with that said the upcoming events is now done and we are ready to focus on the deals chart this is another component that looks something like this it is a complete chart which expands and you can see it's fully responsive we have multiple and you can even turn off or on specific properties even C details this is going to be great the only thing you have to do is feed it the data and it will automatically display it visually so let's focus on the deals and then later we're going to focus on these highlighted numbers at the top so now let's collapse it one more time of course has to look good on mobile as well which it does right now for the events and let's focus on the deals chart to get started with the deals chart we can first wrap everything in a card similar to what we have done with the upcoming events this card will of course be coming from ad design and we're going to give it a couple of properties such as a style property and here we can Define the height of 100% if we save it immediately you can notice how these deals turned into an empty card next we can also Define a title property right here and that's going to be a div that's going to have an icon within it called dollars or dollar outlined like so and we need to import that from Dollar outline L and design icons and we can also Define a text element which we need to import from do/ text and within it we can simply say deals now we can give it a size equal to small or SM we can give it a style equal to margin left of about 0.5 Ram there we go just to divide it a bit from the Icon now this is looking good both for the upcoming events and for the deals let's let's also style this div just a tiny bit by giving it a style property display is going to be Flex align items is going to be Center and then Gap is going to be eight similar to what we have done on the previous card we can also provide additional head and body styles right here on the card by saying head style padding of eight on top and bottom and 16 on left and right and we can also provide a body style that's going going to have a padding of something like 24 on top 24 right zero on bottom and 24 on the left side there we go so this is going to make sense once we actually add the body of the card now within the body we want to render a new component coming from add design and this component will be called area so let's render the area chart and it's going to be a self-closing component that has to have some configure information so we can spread the data that config and we can also Define a height something like 325 should do now creating config is going to be simple at least to get rid of this error and we simply need to define a new con config is equal to an empty object that's it for now but we haven't yet imported the area from anywhere where do we get access to the area chart well to use charts within ad design we'll have to to install the and design plots package which you can see was updated two days ago which is always a good sign and it will give us access to many of these charts so let's simply install it by running the command mpm install add and- design SL plots but before you press enter let's also add a version add 1.2.5 I found this version to work very well with what we're trying to do so just to ensure nothing breaks install this specific version and press enter as soon as it gets installed you can then select the area and press control space and automatically import it from add design plots now it's still going to complain saying that the data is missing in the config so what we have to do is now properly Define this config and the first step in doing that is giving this config a type of area config coming from and design plots now we can know exactly what we have to have within this object you can see we're missing the data property which is the most important one so let's figure out how can we get this data property for now we can make it an empty array and that's immediately going to make it work and we can see a number zero on bottom left which means that the chart is indeed there and everything is done regarding the jsx part but now it's our job to figure out how to get and pass the data and then maybe modify the chart a bit so let's work on getting the data first once again we're going to use the use list hook created by refine that allows us to fetch data from your API so we can immediately say cons data and then is equal to use list coming from refine Dev core and if you remember correctly use list is just a wrapper around usequery or famously known as 10stack query as well we can use it to get the information sort filter pinate and more but first things first we have to provide an options object and then Define the resource in this case the resource will be deal stages because we want to know about different stages of our deals of course since we're using graphql we also have to provide a meta property right here and then Define a gql or graphql query because we're still querying the data and in this case it's going to be dashboard uncore deals undor chartor query and immediately nothing is visible here because we're not using the data yet but we are no longer seeing an error and we can even try to consol log this data to see what do we get back and if we do that and inspect the element right here we can see that we get back an object with six different deal properties new followup under review demo and so much more that's great it is so easy to get the data now that we have outlined everything and this is the second time we're using it you can see how much faster our development process now is now that we have laid down the foundations and I want to point out here at the start it might have seem a bit confusing to use the use list the resource The Meta and I want to take a moment to relay to you that at the start it might have seemed like we're doing too much we're introducing so much code and the question was for what but now I think you can notice it now that we have introduced that code it's so easy to just fetch the data anywhere we need to within any specific file and that's the beauty of refine as well as all of the other Frameworks it provides you with a structure that you can then use through your advantage and know that whatever you're doing you have to do it in the right way and then the framework has your back in this case has your back with graphical queries has your back with typescript types and the way that we're fetching back data and error handling as well so now let's actually put this data to use we can do that by creating a new function const deal data is equal to and we're going to use a react. use memo to which we need to pass a call back function and then return a function call of map deals data which is coming from add for/ utilities helpers and then we pass the data question mark. data to it this is going to nicely filter out or map our different deals so they're ready for use in the area chart of course the second parameter of the used memo has to be an array inste of which we can specify when will the used memo have to recompute the memorized values in this case only when the data data changes so why are we using the used memo here well we're using it to memorize the data so that it's not recalculated on every render and now we can simply pass the deal data right here into the area chart config this will momentarily break the app but I believe that's because we have to provide the x field or Y field as well it's a field that will be used on the xaxis and Y AIS of the chart so we can say x field is going to be time text in our case and the Y field is going to be the value of that deal so if we save it now you can see that we're back and we're actually getting something mapped out right here the value on specific dates this is great but of course this is not telling us a lot right now we can make it much more descriptive before that let's fix this typescript error right here by defining the type of the data that the useless hook will return we can do it like so and specify get fields from list coming from nestjs query refine Dev and then we can also specify what type of fields are we getting by providing another type right here dashboard deals chart query so this way we know exactly what we're dealing with coming from graph quel types which are generated for us by Cen now if you save it you can see it's no longer complaining because it knows exactly what it's getting now let's fix our chart a bit by providing some additional config properties we can provide the is stack property which is going to be set to false and this is used to stack the data on top of each other in this case we don't want that we can also provide the series field which will group the data based off a specific state in this case we want to group it by State there we go so now we have L and one which is great we also want to add the animation which is going to be set to true we also want to add the start on zero to false which is going to ensure that the Y AIS starts from zero we can add the smooth property which will make the chart smooth mean meaning it will connect the points by a smooth curve and then of course we have to make sense of the data that we have in there and for that we can Define the legend first of all we can maybe do a legend offset so offset y to something like minus 6 this is going to move it a bit to the top we can also Define the Y AIS and then Define The Tick count like this and set it to something like four if you want you can do something like six or you can do something like eight as well but that's too much I think four is just fine then we can also Define a label for the Y AIS by using the formatter function formatter which is going to accept a v value of string and call a callback function that's going to return a template string of a dollar amount and then a number of the value but divided by 1,000 like this and then we can add k at the end so we don't have those long numbers rather just 200k 300K 600k and so on let's see if I have done that correctly before we had something like this let me just get back so before if I reload the page right now we had 200,000 and now it's going to say something like 200k that's good looks better next next we can also add a tool tab below the Y AIS so on Hover it's going to show a specific tool tab we can do something like formatter where we get the data and then we can return a name of data. state and we can also return the value of a template string of the dollar amount number data. value and then we can do did the same thing divide by a th000 and then show the K so now if you hover you can see this nice looking tool tip but it's formatted to show the K value and I notice that we do have a problem right here so we can fix it by closing it right here and I do believe it's going to look good now there we go that's much better now you can see all of those changes I think all the way up to here have been just the quality of life changes if I remove them and reload it's still going to look good right we don't have the smooth edges we have maybe uh big numbers right here yeah that are hard to read but then if we do this and reload once again it's so much smoother everything looks better and makes so much more sense so I just wanted to take a moment to teach you how we can further style and design charts great with that said we can also apply some additional filterings to our use list by providing filters which is going to be an array within that array we can provide a single filter with a field of title operator is in and then value is either one or lost that way we won't have any other states we're going to only have one and lost to be sure that nothing bad is happening and with that said we are completely done with the deals chart so let's close it and let's expand our browser to check it out there we go so now we have the deals we can go compare it with the deployed site and on the deployed site it does look like this part takes 2/3 of the screen whereas our current one only takes one additional third so we'll definitely have to play a bit with the layout and positioning but before we do that let's fill out the top of our dashboard with these great looking highlighted cards to create those cards at the top we can collapse it and go back to our homepage that's going to be the index of the home we have our upcoming events and the deals chart and what we want to do is add the cards right here on top but now that I look at it it's going to be easy to also expand the deals to its full Glory so we don't have to necessarily copy the properties from the upcoming events we can rather make it exactly how it should be so to do that let's modify our structure to make space for the cards as well as for the deals we can start by going within our div right here and creating a new row this row will be for the cards on top and that row is going to have a gutter equal to an array of 32 and 32 we can also then create a new column within it and this call will have all the same properties as before extra small small and then extra large which is going to look something like this we can keep it in a single line so it's easier to see and then within this column we can show one specific specific card so within here we can do something like dashboard total count card like this and now we can duplicate this three more times because we have three of these cards on top so if you save that and go back we can see three dashboard total count cards now we want to close this row right here and then we want to open up a new row this row will have the same gutters the same Styles and then also will'll have the second column where this is not going to be eight but rather it's going to be 16 this will allow our deals to extend 2/3 of the screen so now if I open this up you can see the chart takes 2/3 and then these cards right here very nicely extend throughout the full width of the screen but of course if we collapse them you can start notice that they go one below another exactly as they should on smaller width mobile devices so with that said let's create our dashboard total count card so we can use it within our homepage that's going to be a new component within our components folder and then we can go to our home and create a new file called total count card. TSX and there we can run our afce and rename it to dashboard total count card there we go go now we can of course export it from the index TS that's going to be import dashboard total count cards from home count card and then we can export it right here as well of course don't forget to add a comma Now if we go back to our homepage we can actually import all three of these by turning it into a component self-closing one for that matter and we can then simply import it by pressing control space and then it's going to nicely come in from at/ components this now allows us to pass a couple of props to it we'll have to define a resource for each one of these so let's provide a resource equal to for the first one it's going to be companies for the second one it's going to be contracts and for the third one it's going to be deals so this will show a real resource then we can define a special is load property for each three of these so we can say is loading and by the way if you're not sure how I'm doing these multiple cursors I'm holding the ALT key or the option key I believe and then I'm pressing multiple times to open up multiple cursors and then I can just say is loading which we're going to Define really soon and then finally we need to figure out the total count of all three of these so we can say total count is equal to data question mark. data do companies. total count for the second one it's not going to be companies it's going to be contracts and then for the third one it's going to be deals now of course before we actually go ahead and start working on the card we have to figure out where this is loading and where the data is coming from and let me show you how we're going to get access to that data we can again Define const and then get the data and the is loading similar to what we have done with a use list but this time we're going to use the use custom hook coming from refind Dev core then we can provide an options object and Define a URL just as an empty string we can Define the method which is going to be get so it allows us to completely customize what we're trying to get and then we need to provide the meta which in this case is going to be the gql query for exactly what we want to get gql query of the D dashboard total counts query imported from graphel queries and let's dive into this query to see exactly what it returns it's quite simple it goes over the dashboard total counts and Returns the total count of companies contacts and Deals and now that I look at it this is not contracts rather it's contacts so let's modify it and I do believe that typescript would also let me know that soon if we use the proper type so right here with the custom we can Define dashboard total counts query and import it from graphql types and close it and if you do this you can see that now it stands out so much how big this error is property contrast do not exist did you mean contacts yes that's exactly what I meant and we can fix it great now we're properly fetching all of that data but it's complet explaining that the dashboard total count card doesn't accept any props so let's dive into it and let's make it accept some now that we know exactly what we're passing it's going to be quite easy we just need to extract it from here we need the resource the is loading and the total count and we can just Define those as a type of props which we can Define right here at the top type props is equal to first we can start with resource which is going to be either companies contacts or deals then we can have something like is loading which is a Boolean and total count which is a number now that we're getting all of these props let's turn these pieces of text into cards so let's turn this div into a nice looking card coming from Ant D you already know how it goes if we save it already we have three cards let's apply some styling such as a style of height of 96 pixels let's of course properly spell that right here within our code base and let's also apply a padding of zero there we go next we can also apply some body style which is going to be equal to padding of something like eight pixels on top eight on the right side eight on the bottom and then 12 on the left side there we go this is good and then we can also give it a size is equal to small within this card we can have a div and this div will also have a style of its own the style here will be a display of flex turning it into a flex container align items of Center gap of eight between the elements to create some space and then a white space of no wrap there we go within this div we can show an icon for each card so let's render an icon so how would we render a different icon for each one of these cards we could of course do something like icon and then Define as icons for that specific resource like this and then it would know exactly which resource has it has to get it for let me show you how I would approach getting all of this data for these different cards we can create something known as a constants folder this is going to be within source and then create a new folder called constants it's similar to utilities but here you provide constant values which you can reuse across your application think of it like a CMS for your app you don't have to put all the values or text pieces within the jsx itself you just write it here or have a non-developer person write it and then you can simply use those values So within here let's create a new index. TSX and the full constants index TSX will be in the read me down below so simply copy it and paste it right here it's about 300 lines but it's mostly just different labels as you can see so we have different industry options which we're going to use later on we have different status options with the labels and values we have different values for deals as well and then we also have this so this is a specific color of the card the secondary color and even the type of Icon the title and the data which we want to use for this specific card so this now allows us to go back and right at the top try to extract specific values for each of the cards by saying const get the primary Coler get the secondary Coler get the icon and the title which is equal to total count variance coming from ad SL constants for that specific resource we're currently rendering so it's going to be different for all three of these cards let me show you we have our icon and the only thing we have to do is now render this icon right here and there we go we have three different colors as well as three different icons now below this icon we can also render a piece of text which of course has to be imported from the do do/ text and it's going to render a title once again the title will be completely different depending on the card or should I say resource next this text can have a size equal to MD a class name equal to secondary as well as a style equal to margin left of 8 pixels there we go below this text and below the div we can create a new div this div will also have a style equal to display is flex and justify content is space space between like so we don't need align items in this case within this div we're going to show another text and this text we look into if we are currently loading and if we are loading we want to show a skeleton for the button so we can say skeleton. button it's going to be a self-closing component and of course we have to import skeleton from ad design and if we're not loading we can actually render the total count for each one of these cards so if I save it we can see 30 78 and 288 as well let's also provide some styles for this skeleton even though we cannot see it right now such as a margin top to divide it a bit from the top of eight pixels as well as a width of about 74 pixels like so great now let's of course make this text a bit bigger by providing some props to this text element such as the size equal to to xxxl it's going to be a very big one let's also give it a strong property to make it bold and let's give it a style property of flex is one white space is no RAB Flex shrink is going to be set to zero text align is going to be set to start margin left will be set to 48 pixels and we can also apply a special font variant numeric which is going to be tabular Das nums and this right here is numeric not a number so if we fix this and save it this is looking very very nice of course the star of the show with these cards is not the number itself but rather the realistic graph or the chart that appears for each one of these numbers in the respective primary Coler so let me show you how to add that it's going to be similar as we've done with the previous chart right here below the text we want to show the area coming from add design plots it's a self-closing component to which we have to spread the config into and we also provide style which is going to be equal to width of about 50% so that the number takes the other 50 of course we have to define the config as we have done it before we can do that right here here below this resource const config of a type area config coming from add design plots is equal to and then let's not forget the two most important parts which is the data in this case we can get it by saying total count variance which is coming from our constants for a specific resource and then get the data for that specific one we also need to define the X field which is which is going to just be the index so X field of index and then also the Y field of value and if we save it we can already see a great looking chart but of course it's far from looking like this so let's make it look more like that to do that we have to play a bit with the config properties as we have done that before we can add the aend padding property of an array of 1 0 0 0 this will add some additional padding we can then add a padding of zero overall there we go we can then sync view with padding set to true we can make a autofit property be also set to true so it's going to fit it nicely tool tab is going to be false because we don't need to hover over it animation is also going to be set to false we don't need to animate it here then the xaxis is going to be completely false we don't need to show any numbers on the x axis y AIS will look a bit different though it will have a tick count of 12 so that's a lot of lines right here but we might not even need that as you can see in the final one we don't have it more and that later the label or rather the style of the label will be stroke of transparent so that looks like this if you reload you'll notice that there are no labels whatsoever but now we're more interested in the grid so if we go below the label and modify the grid of line style stroke to transparent as well and there we go we hide those lines we also want to make it smooth so it's all the way below this y AIS which we can collapse momentarily and then add a smooth property of of true that's more like it we can then add a line to be of a specific color so line Coler is primary Coler for that specific resource card there we go but we also want to change the area Coler so let's modify the area style have a callback function and then return a new object of fill we can apply a linear gradient right here first we can do something like L of 270 which is going to be 270° of the gradient then we can apply the second one which is going to be zero of hash FFF and then 0.2 as well but let's modify it a bit we don't need parentheses in this case we just need a column so that's going to be like so and finally we need to provide a secondary color and then the primary color so we can say 0.2 secondary color and then one of primary Coler not secondary right here this way it's going to get a special area style and you can see a nice linear gradient how it looks a bit more transparent at the start and then gets to the full color of this primary card so you might have thought that these are just images or illustrations but they're not this is indeed a real chart happening in real time based off of the real Resource number right here of companies contacts and deals in Pipeline and with that done we're done with the dashboard total count card so let's go back to the home let's figure out why it's complaining right here saying that it's possibly undefined so if we go back here we need to make sure that the total count is possibly undefined there we go and now it should no longer complain so with this we're completely done with the cards we're also done with this part of the homepage so now let's expand it and would you look at this reload we have a great looking chart right here which you can notice changed from the last time so we indeed are working with the real data right here which is pretty cool and then all of these numbers will also be changing in real time so now we have the upcoming events we have number of companies contact total deals in pipeline this data in this table can represent anything you want it to the possibilities are endless but I'm just showing you how we can connect this to this mock database and then work to create this dashboard using refine and then using those special use custom or use list properties now let's focus on the last part of the dashboard homepage which is the latest activities card of course that's going to be on the homepage as well so let's go right here below the last row of the upcoming events and Deals chart and let's create a final row that's also going to have a gutter of an array of 32 and 32 and a style of just a bit of margin top to divide it from the elements we just created of 32 pixels within it we can show a column that's going to have an extra small property of 24 so it's going to take the full screen on all devices and there we can render the dashboard latest activities this is going to be a special component which for now will break our application because it doesn't exist yet but if we now go back and create this component within the components home and then create a new latest Das activities. TSX component we can run rafc change this to latest activities in Pascal case and then EXP ort it from the index right here by first importing it latest activities and then exporting it right here at the bottom now we can go back to our homepage and we can import it automatically by just saying latest activities coming from add SL components we can move into it and we are ready to start developing the last component of our homepage which is the latest activities to get started with developing the latest activities let's go ahead and turn it into a card you know the drill don't you so this is going to be a card coming from Ant D and then we can also give it some Styles like we used to do before we can give it something like a head style which is going to have a padding of about 16 pixels and immediately we can see the card appear on the bottom we can also give it a body style with some additional padding such as padding zero on top and bottom and one ram on left and right we can then Define a card title which is going to be a custom div so that's a div that will have a style equal to display of flex align items of Center as well as a gap of eight eight pixels specifically then we can also render an icon right here that's going to be an unordered l list outlined and we can also render a text this text will be coming from the dot do/ text and it's going to say something like latest activities or rather not something it's going to say exactly latest activities we can also give it a size equal to SM we can give it a style equal to margin left of 0.5 REM there we go that's more like it now within this card we can choose what we want to render and first we have to figure out if we are currently loading so for now I'm just going to create a mock variable is loading which I'm going to set to false and then we can create two different loading States well rather you know what let me do a loading state to True first so we can simulate that loading empty window here we can ask ourselves or ask the code if we are loading and if we are we can run a list element coming from Ant D it's going to be a self-closing list that of course has to have all of the properties that the list needs and then also if we are not loading then we can also render another kind of list right here which also will be a self-closing component now for this is loading list it has no data right now but we can also provide an item layout which is going to be set to horizontal and we can mock some data right here here by saying data source is equal to as before we can do array. from where the length will be a specific number such as maybe five right now and then we can call a DOT map on it where we go through these elements we don't need the first Bram just the second one which is the index and for each one we automatically return an ID of index or rather I in this case try to bear with the syntax right here I know it's not as straightforward as we might want but it's just a DOT map with an instant return meaning you need a parentheses right here that returns an object with an ID of I there we go and now you cannot see anything and that's because we need to provide a render item how will each one of these items be rendered well we can do the underscore because we don't need it and then the index and for each one of these we can return the lat latest activities skeleton which is a self-closing component which you need to import and provide a key equal to index and with that you can now see five of these cards nicely loading but now is the time that we switch the is loading to F and start fetching real data within here of course to be able to render it we need to fetch the data beforehand and for that we're going to use our already well-known hook called use list but this time we'll go even deeper into pation sorting and filtering to ensure that you fully understand how does it work so we can say const and we can get the data in this case that's going to be audit data because we have the latest activities which are indeed Audits and that's going to be equal to use list coming from brief find Dev core and we need to provide an object inside of which we can specify the resource of audit there we go if we save it it's still not not going to work why is that do you know well since we're using graphql we also have to provide a meta property right here and then Define the gql query for the request we're trying to make which in this case is the dashboard uncore latest underscore activities audits query there we go diving a bit deeper into it we can see that we're going to have some variables so filtering sorting and paging which we're providing to the audits call and then we want to get the total count of all audits all of the nodes with these specific pieces of information created ad and then even the users that created those audits so going back if we scroll down we still see no data and that's because we're not yet passing these audits into the list down below before we go ahead and pass it let's first extract some of the additional benefits that the used list hook provides to us things such as the is loading which we can rename to is loading audit we also have the is error as well as the error itself now what we can do is conso log now what we can do is conso log the audit to see what do we get back from it let's do it right here and then open up the inspect element under our console and if I reload let's see what do we get back we have a couple of undefined and they keep getting cold which might mean that it's best to close this page because we do have some kind of a loop happening right here but thankfully I believe refine closes the loop for us and makes it not happen again but basically it's trying to read the nodes right here which apparently it cannot do we also have a problem with o right here and that's because I've made a bit of a mistake and I've said audit right here whereas we should have get the resources of audits plural so if I save this right now you can see that we get back data this time for real it has 1,86 six Audits and we have a lot of different pieces of data with different actions for each audit changes created at Target entity user and so much more exactly what we're defining that we want to get back from this gql query but now bear with me we don't simply want to use the audits themselves and then show them right here we want to get the activities from these audits so what we can do is first get the deal IDs so we can say const deal ID which is going to be equal to audit question mark. dat question mark. map where we get each individual audit and we return an audit question mark. Target ID like so so this is only going to give us the IDS and now we can use those deal IDs to make another call then we'll be able to get all of these deals as you can see right here so how do we do that well we're going to fetch all deals with the i these from the audit data by using another used list const data this time we're getting deals with the is loading property which we can rename to is loading deals and that's going to be equal to a use list hle inside of which we can provide the resource of deals so we specify which resource we want to perform the operation on and then here we can even provide create query options this allows us to disable the query if there are no D IDs so we can say enabled if double exclamation mark to turn it into a Boolean deal IDs question mark. length and of course there has to be a comma right here then in this case we can disable pagination by saying pagination mode off and we can also apply some additional filtering keep in mind the app is not working do you know why it's because we we haven't yet provided a special gql query for this call and under filters we can filter out by field is ID operator is in and then value is deal IDs so we only want to filter out those that are within the deal IDs that we get from the Audits and finally we can provide the metadata and here Define a gql query which is going to be dashboard unor latest underscore activities underscore deals query let's see exactly what it does it's getting the deals this time and it's returning all of the deals as well as their total count and to which company does that deal belong to now that we have that if we have any errors we can say if there is an error in that case we can simply maybe consol log the error as well as return the null so we don't see anything in our app doesn't break next if we are loading we can then check both States is loading audit or is loading deals which now we can do and now we're getting the audits from the first list then we map over their deal IDs and we use them to fetch the deals using the Second Use list and now we have the deals which are the actual data that we want to showcase so now going back to our list we can actually provide the data which is is deals we can do that by saying item layout is going to be horizontal and then immediately data source is audit question mark. data now you might be thinking why did we do all of this extra work to get the deals data using another list if we're never actually using it we're just using the audits well that's because the original data source is audits but we're going to use the data from the deals when we render each individual item so we can say render item where we get back the item we're currently showing and then we need to find the deal with the ID from the audit data by saying K deal is equal to Deals question mark. dat. find find me a deal where the deal. ID is triple equal to item. Target ID or undefined there we go so now we're getting that specific deal and for each deal that we get we can now return a list item so list. item and we can provide the list. item. meta which is going to be a self-closing function and to it we can pass all of the data that we might ever need such as a title inside of which we're going to use the DJs Library which we can import at the top and provide to it a deal. mark. created at and then we can call the dot format and format it in something like mmm dd- y y y y-hh colon mm and now if we save it you can see all of these different dates appear right here why are we saying triple mm well that's for Jan or Feb right three letter months then we can do DD for a short date we can do a full year and then even hours and minutes it's so easy to format it with the DJs Library you can even add seconds I believe DSS and then you have seconds as well right but we don't need to go that far in this case let's also provide an avatar for each one of these deals we can say Avatar is equal to and then we can render a custom avatar component which we have created before this time it's going to be of a shape is set to square we can give it a size of 48 a source equal to deal mark. company. Avatar URL and a name is equal to deal question mark. company. name if we save it we can now see this for each one of these but it doesn't really seem to get a real company image and the reason why we're not getting them is because I don't think we are finding the correct deals belonging to specific audits the deal ID could potentially be a string and we're comparing with a Target ID which could be a number so I believe instead of a triple we can use the double equal sign right here there we go that works or we can stringify this by wrapping it in a string Constructor if we reload that works as well there we go let me also put this in a new line so you can better see what's happening we do the find and that looks something like this D ID has to be equal to stringified item Target ID great and now we have all of these companies and the dates let's also apply something else instead of a avatar and title and that something is a description which is going to provide us all of the other information which we might need this description is going to be wrapped in a space property coming from and D with a size is equal to four that can be a number right here then within that space we can have a text property that's going to be strong and it's going to render the item. user.name there we go so we can see admin user for most of these then below that we can have another text which is going to look into the action of that item by saying item. action and if it's triple equal to all uppercase create we can then say created else we can say moved there we go created right below that textt we can have another text that's also going to be strong and it's going to render the deal. tile we can add a question mark right here in case it doesn't exist there we go modern Frozen car then we can add another text right below and this text will simply say deal and then we can add another one below inside of which we also want to look into the action by saying I item doaction if it's triple equal to create then we want to say in else we want to say something like two because created in and moved to makes a lot of sense and finally the last text element that's going to also be strong this one can say deal question mark. stage question mark. tile and save there we go now this one is a bit harder to see on mobile devices but if we expand it there we go you can now see that this makes more sense admin user created recycled fresh towels deal in new there we go in this first one I can see we don't have the admin user here but that's okay for now because all of the other ones have it and we can see the images the dates and we can see all of the different data about a specific deal being made coming right here through latest activities and we have done that by using the combination of two different useless calls so it's doing them one after another first it gets all the Audits and then it gets all the deals and we use the data to fuse it together to get the latest activities with that said we can now scroll up and would you look at that we have all of these great looking dashboard home cards the upcoming events the deals a lot of different charts a lot of stuff is happening here and it's looking great but it's not about this specific information it's not about Michael Scott from the office or the annual company picnic it's about you being a capable developer and utilizing all of the tools that are at your disposal and in this case that's refine when it comes to building phenomenal dashboards and using the properties such as use list to get the data automatically using graph queries and fusing multiple of these together to make complex actions refine scales with you and once you have the setup ready it will scale indefinitely and allow you to build complex applications with that said the latest activities are now complete and with those the homepage is as well before we move to the other Pages let's go back to what we talked earlier regarding refine Dev tools open it up and go to the monitor section so many hooks but exactly the ones we're using nothing more and nothing less if you take a closer look you'll see that it also indicates where we're using a specific hook for example we're using the use one in account settings but if you were to check the form we're not using do hook we're using use form interesting isn't it well the dev tool is telling us that in account settings we're using the use form which in turn is then calling the use one pay attention to the trace details click on it and you'll not only witness the entire process but also the data we are receiving from that hook in that component this is what sets this Dev tool feature apart we can observe the entire success and failure Journey where it kicks off what's happening behind the scenes and the data it brings back to us no more relying on conso logs the same process applies to other hooks like Ed list and more feel free to dive into it deeper to understand the refines concepts in more detail detail but now let's pick up where we left off we have added our latest component right here which means that our dashboard is now done and we are ready to move to the second page of the day which is companies so what do you say that we navigate over to the app. TSX and add the second route right here so we can actually navigate to it we can create a new route which will have a path of forward SL compies and element will be the company list page like this of course we have to create it so we can go to our pages and create a new folder called company list within it create a new index. TSX file where we can run rafc and create a company list component then we can just instead of doing the default we can do a typical export con right here and we can export it from our index DSX as as well by saying export everything from company list which allows us to go back to our homepage and import company list not page just company list is going to be enough from Pages allows us to navigate to it and navigate within our application as well using built-in routing it is as easy as that which means that we are now ready to start developing our company list and now that I mention it it might make more sense to rename our folder to just company which then allows us to call our file list. TSX and of course we also have to modify the import of that file right here in the index now what this allows us to do is to later on create a create as well as edit files within the same folder and of course this one being the company list so with that said let's get started started with creating your company list this is what we're aiming for a table that has one column that is completely searchable another that accumulates deal amounts for that company and then also actions that allow us to edit and delete specific companies as well as a button to create them so without any further Ado let's begin by modifying this div to become a list now this list won't come directly from an D rather it will come from refine Dev and D it's the refin version of a list component allowing us to adding just a tiny bit of magic when it comes to managing lists and resources for example I mean look at that we already have companies as well as a button that says create all of this has been created for us automatically just because we have added a route of companies I mean look at this we already have the company's title as well as a button to create more of course the route is not working yet but we'll make it work soon for now let's display some companies let's apply some props such as breadcrumb which is going to be set to false this just allows us to see the path of our table which we don't need to do at this point in time we can also render the header buttons and in this case we can have a callback function that returns exactly what we need make sure to put this as a parentheses and not as a curly brace because we have instant return and here we want to return a create button coming from refine Dev and D this button will allow us to navigate to a specific path to create new companies so let's make use of refin use go hook const go is equal to use GO coming from refine Dev core this now allows us to navigate to a different path so right here within this create button we can add an onclick function where we have a cack function and here we can go to and we can provide an object first we need to provide a two property which is going to be pointing to resource of companies as well as an action of create it is as easy as that you don't have to define a path or anything you just Define the resource and the action and the path will be done automatically for you right below the two we can also provide additional options in this case keep query which can be said to true in this case we want to merge the current query if we do this the current query parameters will be merged with the new query parameters and also we want to provide a type type can be one of three things it can be push replace and reload in in this case we can put replace so that it completely replaces the current entry on the history stack of the browser and now if you click on create it's going to point us to Local Host 5173 companies new but we haven't yet created the route for that so let's go back and we're going to do that soon for now we need to focus on displaying the table so let's go right here inside of the list and let's render a table component coming from Ant d this table will accept something known as table props and once again refine makes it so easy instead of using the used list hook which we used a couple of times so far this time we're going to use the used table hook so we can say const table props as well as filters and set that to equal to use table it's going to work similar to how the use list works but with some added benefits first of all we can again provide the resource as we usually do of companies and let's not forget that we also have to add a meta property right here to specify our gql query so we can say gql query is going to be equal to company's list query and you can see that now everything breaks that's because we have to import used table from refind Dev and D make sure that it's coming from and and not from core and we can now save it and reload and we can see a table that says no data now let's explore this gql query and we can see that we have some variables which we can later on pass such as filtering sorting and paging and then we return the total count of all the companies and individual companies with the ID name and Avatar URL as well as get the sum of all deals in this company by doing the aggregate of all of the values great now that gives us the table props while we're here let's also add the pagination we can do that by simply saying pagination is equal to and then page size of about let's do 12 elements per page now we can go below and within this table we can spread all of the table props we can then also Define pagination prop inside of which we can spread the table props do pagination and we can save it now we have page one out of three of course what is a table without some table columns So within the table let's define a table. column like this and in this case it's going to be a self-closing component but it will require quite a few props first of all it's going to require a dat data index of name so we know what we're showing in this case we're showing the name of the company we can then add a title for this column such as company title there we go that's better already now let's also do some filtering so we can first specify the default filtered values which will be equal to a call of the get default filter coming from refine Dev core which we call provide the ID and then the second parameter is going to be the filters on its own this won't do anything but it will allow us to do some filtering later on such as when we add the filter icon this icon can be something like search outlined just a simple self-closing icon which we can import from add design icons on its own it's not going to show if we don't specify a drop- down that will show up once we click on the icon so we can say filter drop down is equal to a callback function where we get access to those props and then we can instantly return something so make sure to put parenthesis and then return a filter drop-down component inside of which you can spread all the props and then expand it like so and put a single input within it that's going to have a placeholder equal to ser sech company of course both of these have to be imported from refind Dev and this one too input just coming from at D if we now save this you can see this little search icon on the top right if you click it soon enough will be able to search through different companies now let's turn these titles into something a bit more exciting when we can actually show the image so to do that we have to modify the render of each item by saying render where we have a callback function with the value as well as the record and then for each one we return a space which comes from and design and within the space we can render a custom avatar coming from components custom avatar we can give it a shape which is equal to square a name equal to recordname as well as a source equal to record. Avatar URL and if we save it you can now see all of these great company logos below our custom avatar we can show a piece of text and that text will have a style equal to Whit space no wrap and has to be imported from components text and can say something like record. name there we go so now we have the company and the logo that's it for the First Column and we can move on to the next one the next one will show the open deals amount allowing us to aggregate of all of the deals for a specific company so let's create a new table. column and we can also provide a type for this component right here saying that it is a company so we can do it like this company and we have to import this from graphql scheme types this way it's not going to complain about the record because it will know it exists and we can do the similar thing right here table column and then add a company as a type pretty interesting way to use typescript now the second one will have a data index equal to total revenue and here we can also add a title of open deals amount pretty simple so far it immediately shows up and and we can render a new item that's going to have a value as well as the record and we want to immediately return a piece of text right here that text will render the currency number coming from utilities and we can pass to it a company question mark dot deals aggregate question mark do zero do sum question mark. value or zero so we're passing the current information and I notice that here we can call this company which makes a bit more sense so we're getting the current values of all the aggregate deals coming back right here and how do I know that this company has it well first of all I can check it out in the type if I go here we can see aggregate such as deals aggregate right here which is exactly what we used or I can go to our graph query and see that we have deals aggregate which is exactly how we called it right here great with that said we are returning it the second column is there and we can focus on the third column which will be the actions column allowing us to edit and delete our rows so right below this one let's simply copy it for now and duplicate it this one will have a data index of ID it's going to have a title of actions it's going to have a fixed off right so it's always fixed to the right side and within the render we simply need to get back the value and we can return a space element and within it we can render the edit button which is coming from refine Dev and d and we can pass to it a hide text so it's just the icon a size of small as well as a record item idal equal to value that we get back and now if we save this you can see that we immediately get the edit button and we can duplicate it and also get the delete button which we can import from refind Dev antd this is how seamlessly everything works together once you use the power of the framework that is given to you keep in mind we are within this current Table this table gets all of the props passed right here and it knows that this is a table that's showing the companies and because it knows that it can automatically generate the buttons for editing and deleting specific nodes within that table so now if I click edit right here you're going to notice that the URL is going to change to companies edit one and even though we cannot see anything on the page yet we know that the routing works and now we simply have to implement that route similar thing for thead as well as create but hey at least we know that now our list is there so now if I expand it a bit you can see how it looks like looking great on tablet devices and soon enough we're going to implement the search as well as some additional filtering so let me show you how simple that is everything is happening within this used table similarly to what we had with the used list before right below the pagination we can apply something known as sorters and these are used to sort data with any query it's an object that accepts initial sorters so we can say initial and that is an array of different sorting possibilities we want to use such as field created ad and we want to sort that in order of descending so we can just do this I reloaded and there it is now alongside sorters we can also apply filters so we can say filters and then we can add an object where we provide initial and then we can add an array with all the filters for example we can do an object where field is name and the operator is going to be contains and then the value of undefined so we want to filter out all of the undefined values and I just noticed initial should be an array instead of an object so if I fix it we are good so pagination sorting filtering it's all there what do we need well here you can also add the on search functionality so right here below the resource we can say on search which is going to be a callback function that gets the values of the search and then you can return an array that contains an object based off of which you want to to do the search for example field is name operator is going to be contains and then value is going to be values. name and of course we have to add a comma here so now if you save this if you go to this search and search for something like let's do this one right here and filter you can see that it automatically works right out of the Box because we implemented this function it goes ahead and applies filters to this entire table and automatically this table reflected because of the table props and this means that we're officially done with the list now that we can see the list we can focus on adding new companies to our list by making the create button work so let's do that next and you might wonder how do we even approach doing that well don't worry we're going to we're going to go through the process a couple of times so let me show you how to do it with the companies you might remember that we have created the list before and this list is within the company folder so right here we can also create a new file called create. TSX and run our fce here we have a create component which we also need to export from this index so we can export everything from company create meaning we have to create a route for it and you know where all of the routes are they're within the app. TSX right here where we have the company's list we can also add the company's new so let's turn this route into a route Group by opening it like this and then within path companies we don't have to render the element right here rather we can render a child route right here that's going to be be a route that's going to have an index property meaning it is just companies and then the element is the same as it was company list but now we can also create a new child route which is going to be route with a path of new and the element is going to be company create page or I think we just called it create page or I think we just called it create which is coming from from Pages company create and if we save it and go back to our current application we can press create and indeed it does point to the create we can see that right here if we paste create a couple more times we can see that we are right here and we are ready to start developing it if you think about it this is going to be our first modifier action the first one that is not a query but rather a mutation so let me show you how to do it first we're going to wrap everything in a company list this is the same component we have created before it's coming from SL list there we go so it's exactly the same thing as before but now within it we can also render a model which is coming from Ant D this model will of course have to get some props and where do we get props from and so far you already know where do we get props for list or tables we get them from refine Hooks and the situation is going to be exactly the same here you can start noticing the patterns in the structure emerge we can say const form props as well as model props is equal to use model form so this is a special refine Dev ATD type of form to which we can provide options first we need to provide the type of the action in this case it's create because we want to create new companies then we can set default model visibility in this case to true because we are already on the create page so we can show it we also need to specify a resource of companies meaning what are we creating we can specify if after mutation or form submission we want to redirect in this case we can set redirect to false because we're already there then we need to choose a mutation mode and that's used to determine how a mutation should be performed for example they can be optimistic pessimistic or undoable in this case we want to have a pessimistic update so we can say mutation mode is going to be pessimistic what does that mean well it means that the redirection and UI updates are executed only after the mutation is fully successful then we can have an on mutation success meaning what's going to happen after the mutation success and we can simply navigate and the way that we're going to navigate we're going to do it with a goto function so we can once again use the const go is equal to use go which refine uses for navigation and then we can Define the new function called const go to list page which is a function that calls the go method and passes the the two property of resource is companies and action is list so we simply go back to the list with the options of keep query set to true as well as the type is set to replace because it's a model so we wanted to replace it because we don't have to go back to the model it's just there we closed that so now we can use this function go to list and call it on mutation a success finally and most importantly we need to provide the meta tag or The Meta property where it's going to be a gql not a query but finally for the first time ever in this video a gql mutation of create company mutation we can command click it to see how does it work it's a mutation that creates a company based off of the create company input and it just creates a company and returns its ID and the sales owner's ID that's it and whenever you want to learn a bit more about how these queries invitations work you can just go to API CRM refind Dev graphql and just paste them right here and you can immediately see the full input it might make more sense with more detailed code highlighting then you can provide some query variables in this case the input and you can call it and play with it within the playground it's a bit easier with queries as as you can visually see what's happening without having to even input variables but in this case we'll test it in action so now that we know how does this create company mutation work and now that the used model form has all of the options it needs we can now pass the form props to the model we can do it in a similar way of how we did it with the table spread do do dot model props then we can also add a property called mask and we can set it to true this determines whether a mask is visible underneath the model when this is said to True you'll be able to see that semi-transparent dark background right here we can also call the on cancel property what happens there we just call the same goto list page we want to navigate back to the list we can add a title of create company and a width of about 512 pixels now if we save this we are now on just the company's new and if we click create nothing yet happens because there's nothing within the model so let's render a form this form will also accept some form props coming from the same used modal form so that's going to be dot dot dot form props and the layout will be set to Vertical of course the form has to be imported from antd the form itself has to have some form items so let's add a form. item this first one will have a label equal to company name and a name equal to name and we can also add some rules such as the object with an array of one rule where required is set to True within it we can render an input coming from Ant d it's a self-closing input that has a placeholder of please enter a company name now if we save it we should have enough to be able to see our model but still nothing happens and that's because our company list is not yet made to accept children so to fix it we can go into it and make sure that it gets children right here under props and we can add a type of react. props with children there we go and now we can use those children right here within this table or rather that's going to be below the table if we go down we have the table we have the list and then right here below the list we can render the children but of course we have to close it so we can wrap everything in a single div and of course we have to actually open up the div right here on top if we save it now we have a beautiful model because now company list can accept and show children elements and here we have our first input to enter a company name I believe to create a company we need two different inputs we need the one for the name and then we need to tie it to a specific sales owner so to do that we can add a second form input form. item this this one will have a label of sales owner a name of sales owner ID and rules of required as before which is said to True within it we're not going to render an input rather a select element coming from at D this select will be self-closing it will have a placeholder equal to please select a sales owner owner and this one is quite interesting it immediately shows but we have absolutely no data right here to refer it to we need to pick some sales owners from our database and conveniently refine exposes yet another hook called use select it's almost like whatever you're using be it a model or a list or a select there's a hook that helps you to use it to its fullest potential and simplifies dealing with crowd operations so in this case let's define a const get the select props and query results which is equal to use select like this this use select is going to refer to the resource of users because we need to get the sales owner and we can provide it an option label of name and a meta property to know what we need to fetch and a gql query of users undor selector query which we can import from queries this is how it looks like in this query right here we're getting the users with three variables filter sorting and paging as usual we get all users we get the total count of all users and then get specific fields for each user such as ID name and Avatar URL with that we now have to select props and query results so let's import the use select coming from refind Dev and D not from refind Dev core and let's use it right here within the select you know the drill we can simply spread all of the select props and immediately you can see how it pulls all of the users from the database for us even tabas here now let's also provide some additional options for the select by saying options and then here we can choose how do we want to map over the data and what we want to show for each one so we can say something like query results data question mark. dat map where we get each individual user and for each user we automatically return meaning parenthesis and then an object values of user. ID as well as a label that's going to render a new component called select option with Avatar so instead of Simply showing a title or a name of that person we can render this component and to it we can pass a name equal to user.name as well as Avatar URL equal to user. Avatar URL or or if that doesn't exist undefined so now we can create this simple component by going to components and then creating a new file called select Dash option- width Das avatar. TSX and we can develop it by running RFC this is going to be a select option with Avatar that accepts two props the Avatar URL the name and sometimes there's also going to be a shape and we also need to define those props so let's Define the types at the top type props is equal to it's going to have a name of string a avatar URL which is going to be an optional string and it's also going to have a shape which is going to be either Circle or Square great now now we can return a div or rather before we return anything let's just make sure to use this within our component so going back here we need to import select option with avatar coming from components select option with Avatar and if we reload nothing is showing let's try to see why that is if we go to the console we can see cannot read properties of data I'm guessing that's coming from here query results that's because it's query result not results this is my bad and typescript was kind enough to already let me know that it doesn't exist maybe we need to use Query result there we go so if we fix this now we can see that we get a list of nothing because we are now yet to return something and that something is a div that's going to have a style equal to display of flex align items equal to Center and a gap of 8 pixels within it we can render a custom avatar which we had before to which we can pass a shape of shape a name of name and a source of Avatar URL if we save this you should be able to see a lot of friendly faces now the only thing they're missing is a name so let's surrend a text element which we can import from SL text and within it we can render a name so you can see how to make this custom we had a name and now we have connected the photo and the name and it's all here within this select element here if the data is undefined we need to return an empty array so we can say question mark question mark empty array right here so it's not going to complain and also we can define a type of what data data is coming back from the query result so that this user knows that it actually has access to the ID so we can do that right here within the U select where we can Define get fields which is coming from nestjs query and then we can Define users select query from graphql types and this way if we save it it's complaining right here below I think that's because we said just get Fields but we instead need to get get fields from list yes this is the correct one because then it has the option label great so now you can see that we have our create where we can enter the company name such as JavaScript Mastery and we can choose a sales owner such as the admin user or Michael Scott but you can see if we click it it seems like nothing is happening the value is not populated so let's figure that out if we scroll just a bit down you can see that I typed values here instead of value as soon as we fix it to Value enter JavaScript Mastery and then choose Michael Scott as the owner that works perfectly but now the question is what happens when I click save does it just work let's try it out there we go we have the loading we have the alert happening automatically we have JavaScript mastery as the new company with zero open Deal amount which is exactly how it should be at the start this is great we have just implemented the create action let's expand this a bit so we can see it in its full Glory I'm going to click create and we're going to enter something like let's do the office and the sales owner is going to be let's do Dwight and click save immediately in Real Time with a popup and automatic update we can see a new row get added to the database now that we have the list we have the search as well we can filter the values finally let's go ahead and implement the edit that's going to be a completely new route so let's put this side by side and let's go back to the app TSX and let's add a new route we can duplicate this one and modify the path to say edit SL colon ID because it's going to be dynamic and then we can create a new page you know where that page is going to go it's going to go within Pages company and we're going to call it edit. TSX run RFC we can create a new edit component and we can automatically export it right here from company edit then we can go back back to app TSX and we can import edit coming from Pages company edit now if we reload you can see that we have an empty edit page which makes it a perfect empty slate to start working on the editing functionality and just to remind ourselves this is how it should look like on the finished version you click right here and you have this beautiful form with even the contacts right here on the bottom but the form is the key part right here so let's turn this into this to get started with the edit functionality we can first wrap everything in a div and then within that div we can immediately show the row of course the row coming from Ant D then right within it we can show a column also coming from an D and we can Define some gutters and sizes so first let's do a gutter for the row of an array of of 32 and 32 and for the column on extra small devices it can take the full width and on extra large devices it can take half the screen now inside of here we want to render the edit functionality coming from refine that's refine Dev and D but it's not edit button it's rather the whole edit form so it looks like it doesn't allow us to autoimport it but if we go here and say import edit which is coming from at refind Dev sland D we have our edit oh the reason why I didn't give it automatically is because there's an import declaration conflict with the local declaration so we can change this over to something like edit page there we go now we're good now this edit has to correspond to a specific form and you already know the drill we can use the use form hook coming from refine by saying const destructuring something and then saying is equal to use form coming from refine Dev but it's again going to come from the refine Dev at D because it's connected to the form from add design now this hook call will accept some options such as redirect which is going to be set to false as we don't want to redirect and also the meta property which is going to be equal to a gql mutation once again because we are updating the company so we can say update company unor mutation and if you look into it you can see that we accept the input which is going to contain all of the properties needed to update the company and then we return the updated information now here I should have used just the Boolean variable not a string once again tab script saves me there and then we can destructure some things from use form such as save button props form props form loading and query result now we can use those right here within our edit first let's pass the is loading equal to form loading let's pass the save button props equal to save button props and a breadcrumb set to false if we save it still nothing is showing up here that's because we're going to put something within this edit and that something will be a form so let's import the form from add D and let's give it the dot dot dot form props by sprinting it and giving it a layout of vertical of course a form has to have something within it so right here we can render our custom avatar and we can self close it now why custom avatar that's because it's the first thing right here within our form so let's just provide it a shape which is equal to square let's give it a source equal to something like Avatar URL and this Avatar URL will be coming back from the query result so we can say something like const the structure the Avatar URL as well as the name which is equal to query result question mark. dat question mark. data once again or just an empty object so we don't have any issues now if we save it we might need to pass additional props such as name where we get name initials from utils of our specific name and finally we can also pass the style of width of about 96 height of 96 as well and a margin bottom of 24 pixels now if we reload looks like we have an error so if I inspect and go to console we can see canot read properties of undefined reading split at get name initials so it looks like we're not getting back the name in that case we can provide or an empty string there we go so now that works and we do get back the custom avatar because it doesn't have the name but it does have the photo now right below the custom avatar we want to show a select field right here in this case the sales owner and this is exactly the same select that we used in the previous component so we can just reuse it here as well let's go back to our create that's going to be right here and let's grab this entire form item with the Select Property and let's just paste it right here below our custom avatar that's right here we of course have to indent it and modify the label to be sales owner that's good name is going to be sales owner ID and we don't need required in this case but we do need initial value which is going to be form props question mark. initial values question mark. sales owner question mark. ID and we don't need double curly braces right here so this is going to pull the initial value from the form we need to import select from at D and let's not forget we have to implement the use select hook so going back here we can also copy this entire part for the use select hook and just paste it right here above the return we have to import the use select from refind Dev and D not the core they care here and also all the types and these types right here and the user select query now we should have almost everything we need for our select but it does complain a bit here about the query result and that's because we have already refer to the query result here so we can rename it here to query result users and now I can just use this variable right here below query result users and and we also need to import the select option with Avatar and now I believe we'll have everything we need so if we go back there we go tabby was immediately selected and we can select another user as well so now we have the select which we have created for the create company in this case we do want to modify the select just a bit by providing it a pagination which is going to be set to mode off we don't want to pinate over these we want to show show all of them so now this is looking good to me now let's go below we have to implement the company size which is going to be another select of course much easier than this one because we won't be pulling anything from the database rather we can just go below this form item and create another form. item which is going to have a select within it a self-closing one with options equal to company size on options coming from add SL constants and that's it you can just choose the value right below it we need to implement the total revenue which is going to be an input with an icon so let's create a new form item below form. item this one will have the input number coming from Ant D and we can give it a couple of things such as auto focus because this is the first input besides the selects we can give it the add-on before equal to a dollar sign that's going to look like this the Min value is going to be set to zero the placeholder will be set to something like 0 0 0 and if we save it you can see that now we can actually type something and we have real values you could go ahead and Implement a formatter here as well to format the commas for decimal points but in this case I'm happy with what we have here and finally we need a couple more inputs for the industry business type country and the website so let's add them one after another below this form item we can create a new form. item and within it we can create a select field this select is going to have options equal to Industry options coming from constants and we can duplicate this form item one two three times all of these form inputs also need to have labels not the selects but the form inputs so let's select all of these create cursors and then say label is equal to an empty string the first one is industry the second one is going to be business type the third one is country and the fourth one is website if we save it we have this now on the second one we're going to have business type options coming from constants country is not going to be a select rather it's going to be an input coming from Ant D and instead of options it's going to have a placeholder equal to Country and a form input is going to have a name of of Country 2 and finally the last one is also going to be an input with a placeholder of website so let's do it like this and a name of website as well so we can connect the form item with the input there we go that's good and the values are pre-filled based off of that name we can also choose the industry and the business type now if we try to change the sales owner to somebody like oser we can press save and successfully updated company now if we go back to companies you can see that we have our Goldman Sachs and right here we have Oscar Martinez now if we go to the deployed version of the website and choose a specific company you'll see that right here at the bottom we'll also have a new table that says contacts which is a complete table with name we can search for it title and St stage even that allows you to filter different values it's cool that here you can filter by a specific select field not just by the input field and finally you have actions like email and phone call this is cool and all but we have already built a table it's this one right here so let me simplify this for you you can go right here to our company and create one final file right here called contacts dasht . TSX in the read me down below you can find the complete contacts table copy it and then paste it right here and with it we also have to provide an additional contact status tag which is going to essentially just color out these different tags that you can see right here so let's create it by going to components and then create a new folder called Tags and then within here create a new file called contact Das status dt. TSX and once again in the read me down below you can find the complete contact status tag copy it and paste it here it's basically a glorified switch which looks into the case and then modifies the icon and the color for that specific tag we're showing so now we can go back here we can remove all of these Imports and manual import these components such as text coming from add/ components text import the custom avatar from components custom avatar and import the contact status tag from components as well if we save this we can now use this contacts table right within the edit So Below the last call create a new call that's going to have an extra small of 24 and an extra large of 12 meaning just just half the screen and here we can render the company contacts table imported from do slash and save it now if we go to our current website and scroll down you'll be able to see a beautiful contact table that works right off the bat and it's built on top of the same principles that we have used before such as the use stable where we just specify the resource for which the table is to be used we do some sorting filtering I went ahead and commented everything out so you can fully understand what is happening here but once again it's just using refine and Design Elements and then using corresponding refine hooks to Simply pass the props and make it work right out of the box so with that said if I now expand this edit company it's looking like a real dashboard we have a complete list which works in real time where you can create a new company by using this model or you can edit it by pressing this icon and here you can enter all of the details such as Enterprise you can enter a specific amount industry business type and press save it's going to successfully update the company and on the right side you can also see the contacts or the people belonging to that company with complete sorting and filtering capability don't forget that you can also pinate this in case you have more contacts you can also refresh this or go back to companies finally let's check the delete if we try doing it on this Johnston and press delete are you sure we are and like that successfully deleted a company is build right out of the box simply by using remember what we have to go to the list of the companies so that is list component and then here we're simply using the delete button provided to us by refine that when you try to delete something a popup shows and then it executes the use delete for our specified data provider we didn't have to specify anything else zero functions we just provide the record Item ID and make sure that the table gets its necessary props and Define the resource right here within the used table and that's it it works right out of the box with that said our dashboard is now looking fantastic and with it also are companies the dashboard just shows the data whereas in the companies we have full crud functionalities such as list where we can see all of them create them update them and delete them with that said let's navigate to our next big page in this dashboard which is is tasks and inside of here we're going to implement a complete can band board yep I'm talking full apps like Trello or jira right here within our dashboard that's going to be quite exciting so let's collapse our browser close all of the currently open files and start by creating the route for the tasks we can do that by going to our app. TSX create a new parent route like we did for the companies where we can Define the path equal to SL tasks and then within it we can create a new index route that's going to render not the company list but rather the tasks list so let's create a new page right here or rather a new folder within Pages called tasks and within it we can create a new file called list TSX run rce call it a list and import it right here that's going to be list coming from Pages tasks list we have an empty slate inside of which we can start creating our list to get started with our list we can first wrap everything in an empty react fragment and then right within it we need to wrap everything in a can ban board containing that's going to look something like this of course this will temporarily break our app as we don't yet have this component and right within it we need to create a new can ban column just like so these are the two primary components which will form our Canan board so let's create the first one by going to our components folder and right within it we can create a new tasks folder and within the task we can create another folder called canvas Ben and within Canen we can create a new file called board. DSX within there we can run RFC and we can rename it to Canan board container there we go that's one now when it comes to the board and the container itself there's going to be two things so we don't want to do an export default here rather we want to export just the kban board container but also export const can ban board so we're going to have a board as well as the container as two separate exports from this file so let's also export this one there we go and for now we can put a return with just a div that's going to say board there we go and we can also create another file right here within tasks still within cban which is going to be a column. TSX where we can run our fce and just call Canan column there we go now we can go back into the list and we can import all of these components can ban board container as well as a can ban board coming from this file and we can also import the canbin column from the column folder there we go so this is the structure we have the canbin board container within it we're going to create a can ban board and then within the board we're going to have have multiple columns so let's just nicely space this out this is one column and we can duplicate it to signify that there's going to be another column as well great I hope this makes sense and right now you can see that it's complaining because it accepts some children property which we have to specifically Define within those components so let's get started with the Canan board container and the Canan board itself the Canan board container will of course accept children as the only prop and it can be of a type react. props with Children Here we have to wrap everything in a div with some specific Styles so we can define a style and those Styles we're going to Define later we can have another div within this div that's also going to have some additional Styles which we're going to Define later but the most important part is that within those divs we can render children this now allows us to show the board Within in the can board container which is just going to provide the styling for this entire canb we'll use something known as a d andd kit it's a drag and drop feature it's lightweight performant and accessible and just allows us to drag and drop different stuff of course we need this for our Canen you can see exactly how they're doing it here something similar to what we are going to do with our Canan board so with that said let's simply install it by copying this command and paste it mpm install at DND dkit SL core and we can paste it now as soon as it gets installed we can use it right here within our Canan board we can do it by wrapping everything within a DND context imported from DND kit and of course we can close it at the end and here we're going to also return children which are going to come right here from props children and here we can also say this is a react. props with children there we go so now we're wrapping the DND context and we have the children right here and we're also exporting the board container so now if we go back you can see that we have two campon columns because both the board container as well as the board simply return what is in there which in this case are the children so let's start by applying some styles to our canbin board container the outer div is going to have a width of about we can use calul to calculate it and we can do 100% plus 64 pixels this will give us some space to work with we can also have a height equal to that's also going to be ca and that's going to be 100 VH minus 64 pixels I believe that's the height of our Navar display will be set to flex justify content will be set to column and margin will be set to minus 32 pixels now within the outer div we can give it a width of 100% we can also give it a height of 100% as well we can give it a display of flex a padding of about 32 pixels and the Overflow of scroll there we go I know this is not much but we're just starting to create the outer structure remember this is the structure we're going for we can add new cars and everything fits nicely within this window so finally let's go back to our list so now let's start focusing on the inner structure of the Canon board by creating our Canon columns we can first wrap everything in a div and this div later on will also have a reference so we can say ref is equal to and this reference will be coming directly from DND D core so right at the top we can say const we can destructure the is over property which is a Boolean indicating whether a draggable element is currently hovering over the target then we're going to also have the set node ref which is a function to pass to the ref prop of the element you want to make droppable and finally we have the active property which is an object containing information about the draggable item that is currently being dragged so we get all of this when we make it equal to use droppable coming from D and D kit core we also have to provide an options object with the ID as well as data for now we can leave those two things as they are and now we can use the set node ref and pass it to this div right here great now let's apply additional styles to this div by giving it a display is equal to flex a flex Direction equal to column and a padding of zero and 16 pixels on left and right within this div we can create another div for now we're just creating the structure that's going to have the style equal to padding of 12 pixels on all sides within it we can create a space property just to of course provide some space this has to be imported from ad design and this space can have a style of width is 100% and it will also have a justify content of space between there we go now within this space we're going to have another space and this space will render a text element this text we already know it's a component for rendering all kinds of text and for now this text can render the title of a specific to-do so it's going to be title Todo and already we can see the columns that we're creating we have have two of these as I have rendered two columns in this list let's style a bit this text by giving it the ellipses property equal to Tool tip of the title we're trying to render so title to do so in this case if the task is very very long if you hover over it you can see a full one and right here you can just see the base one that's shorter and easier for us to show we're going to make this Dynamic later on next we also want to increase the size so let's put this this in a new line Ellipsis as well and we can say size is equal to XS it's also going to be strong and we can give it an additional style of text transform of uppercase as well as a white space no wrap that's exactly what we want to do there we go now let's see what else does each task has to have here we're just creating the to-do and then the batch of the tasks within that board so we have to-do three and we have to create this badge right now so going back let's provide that badge right here below the text and we can do that by saying if exclamation mark exclamation mark count so we convert the count from a number to a Boolean and if it exists then render the badge component coming from and D like this and pass to it a count is equal to count of course of course the count is undefined now so right here at the top we can Define the count equal to something like zero right now in which case it doesn't appear but if it's two you can see that we get two right here that's looking good to me you can also Define a color within this badge so let's do something like color is Canan there we go that's more like it now below this space right here we can render a button coming from at d and this button will be self-closing it's going to have a shape equal to Circle it's going to have an icon equal to let's do a plus outlined we're going to use this to add new to-dos to that specific column and on click we want to render a function called on ADD click Handler which of course we have to Define right here at the top for now we can say const onad click Handler is a basic Arrow function there we go now we have pluses right here looking good finally below this space right here we can render a description which is also going to be a real variable so let's make it Dynamic immediately as well as the title just to mark all of these details K's description is equal to let's do something like description we can also Mark the title cons title is equal to title that way instead of just saying Title Here we can use the real title which we're going to later on make Dynamic and we can do a similar thing right here and right below the space we can render the description there we go this is looking good now below this div containing the description still within the other div we want to create a new div and this div will have a few Styles starting with the flex property of one overx flow Y is going to depend on whether this field is currently active so we can say if active and I believe we're getting this value from the draggable or the droppable yep that's the case if it's currently active then we want to change the Overflow to unset usually it's going to be set to Auto similarly we can also play with the coer or the border so we can say border is a two pixel dashed transparent and of course is that supposed to be border and also we can change the Border color if the drag is over in that case we can give it a color of 00 0 0 040 else we can do transparent so now if we save it you can see those just small lines right here nothing noticeable right now and we can also give it a border radius of something like four pixels finally let's style the last div within this div and this one will also have a style equal to margin top of about 12 pixels it will have a display equal to flex a flex Direction equal to column and a gap of eight pixels and let's make this a string and right within here we want to render children yep the canand column will also have the children which are going to be the actual elements so we can get it right here at the top coming into the component children and we can Define this as react. props with children now if we save it nothing much is going to change but now our column is almost done when it comes to the layout and we are ready to pass some things into it and of of course the thing we're going to pass within it is going to be a Canan item it's going to look like so and this item we can also create by going to components tasks Canon and then item. TSX run RFC call it a Canan item and then right here we can import it from components tasks Canan item and dive into it to start developing it keep in mind that in the list or rather in the column right here we had the use droppable which you use for the container you want to drop the items within but then for our item we're going to use another hook coming from drag and drop and that's going to be use draggable because item is the one you drag and drop into the droppable zone so right here we can say const and then we can get access to the attributes attributes is an object containing everything thing that we should use to spread on the item to make it draggable we also have listeners which is an object containing event handlers to apply to this element we have the set node ref which is similar it's just a reference to the node we have the active contains the information about the item currently being dragged and we simply call the function use draggable coming from DND core to it we have to pass the ID which is the unique identifier of the item we're dragging we're going to do that later on as well as the data and now as before we can start creating the structure for this Canan item by wrapping everything in a div that has a style equal to position is relative within it we can have a div that's going to act as the primary node so we can give it a ref equal to set node ref we can then spread all of the attributes as well as all of the listeners this is how you use the DND kit we can also give it him Styles and those Styles can be modified depending on what are we currently doing with the item is it sitting idle or are we dragg and dropping it so let's give it an opacity that's going to depend on the active State and if active. ID is triple equal to the ID we're working with that we're going to get through props so we might do that as well immediately we get children we get ID and we get the data through props so let's also Define the types of react. props with children but this one also has some additional props alongside children which allows you to Define them like this props with children and then you specify props as well which we can Define right here interface props and interface is just a different way of defining a type we have an ID of type string and we have data which is optional and it's of a type use draggable arguments that we pass data to this is provided to us by dndd kit core so now we have the ID in the props as well and if that is the item we're currently dragging the opacity is going to be one else it's going to be 0.5 else it's going to be one right here as well next we want to have a border radius of about 8 pixels we want to give it a position of relative and we want to give it a cursor of grab this definitely isn't one that you use often but it's perfect for this use case so now you cannot see it because nothing's there but soon enough you will within this div we want to create an optional piece of code depending of if if this is the item we're currently dragging so we can say if active question mark. ID is triple equal to the ID we're on in that case we want to render this we want to render the drag overlay and that's coming directly from the andd core we need to pass it a z index of 1,000 that's because and design cider has an index of 999 within it we can render a div and that div is going to have a style equal to border radius of about 8 pixels and we also want to provide it a box Shadow and now we can really play with this box Shadow just by Googling a box Shadow generator it can give you some nice box shadows and you can even modify them around so if I go here and modify it you can notice how it changes in this case we want to have some simple box Shadow for or card and we have plenty on the internet as well we want to use something very simple there we go you can choose one here I like this one or this one is also cool so you just click it it's going to copy some box Shadow Styles and you can simply paste it right here we don't even need this part there we go box Shadow you put this in a string and make sure that it says box Shadow like so and also the cursor right here here is going to be set to grabbing there we go so now if we go back we cannot see anything and that's because we aren't rendering the children so now we want to show anything that we pass into this item right here as that item so if we go back here canaban item we can now say this is my first to do and save it oh it appears that we cannot yet actually see it why is that well if we go to Canan item we can see that we are referencing to some kind of an ID that right now is just empty so even though we're passing it we're not really using it and therefore this is not going to match so it will not show but if we show the children right here outside of this Dynamic block of code we can actually see this is my first to do and it appears to be draggable but it's not yet fully draggable so everything we've done so far is great but now what do you say that we actually fetch some data from the database real data using refine that would form our tasks and then we can distribute those tasks across all of the columns just like so and only after we have the data we can start focusing on creating this final piece of UI which is a card that shows the most important information about a specific to-do at a glance so let's focus on getting that data data we can do it by using our well-known Ed list by saying const data renamed as tasks is loading renamed as is loading tasks and that is equal to use list hook call which we can import from refind Dev core now to it we'll also have to pass the resource which in this case will be tasks for our Canan board and also the meta property to pass the gql query for fetching that and that's going to be just a simple tasks query and if we look into it you can provide some filtering sorting and paging and then we get back the total count of all tasks as well as ID title description due date and everything we need about that task as well as the user details associated with that task while we're here we can also provide some additional sorting options such as we want to apply a sorter or sorters where we want to sort tasks by due date in ascending order so we can say field is due date and order is ascending order next we want to disable pagination for this one so we can say pagination is going to be mode off off and that's it for now now let's see if we're getting any tasks back we can consol log tasks right here and we can open up an inspect element and then console to see an object that indeed has 16 tasks right here which is looking great but it's not only about showing tasks we have to know where to show these tasks we have to group them by columns and we can call these columns stages this is the unassign stage the to-do stage in progress in review and more so first we have to map over all of these stages and then map over the tasks within each stage so for now I'm going to collapse this list right here and I will create a new list on top of it const data where we rename it to stages is loading is is loading stages and we call it as a regular use list in this case the resource is going to be task stages and we can also apply a meta property where we're going to add a gql query of task uncore stages undor query and this one what it does is applies filtering sorting and paging and then Returns the ID and the title of all the different stages while we're here we can also filter out the stages so we can say filters and we only want to get those where Field title includes so we can say operator in value an array of Todo in progress in review and done so we only want to filter out those stages that have these values we can also sort it out by applying sorters which is an array of one sword that has a field of created app and it's going to be sorted by ascending for the created ad property there we go and of course this right here has to be an array because we can have multiple sorters within it and now we have the list that fetches the stages and right below it we fetch the tasks but there's one specific options that we can apply to it which is query options and here we can say enabled only if no no stages I like to say no no for this one but it's just a double exclamation mark which turns whatever this is which could be a list of Records into a Boolean variable meaning only fetch tasks when stages are fetched and they exist so now we have two of these used list which are going to be incredibly useful in showing all of the data but of course now we have to fuse the two we want to group tasks by stages so we can say const task stages is equal to and we're going to even use a react. memo or rather use memo to memorize the result of this we don't use the use memo too often and you might not have used it at all ever but it's incredibly useful in this case where we're going to memorize the result so that it's not recalculated on every render but only when stages or tasks change so right here we can add stages and tasks in this dependency array this is going to optimize our application further then we want to check if stages or tasks are not present and if they're not we can return an empty array by checking if no tasks question mark. data or no stages question mark. dat then we want to return an object that is going to say unassigned stage is an empty array and stages is also an empty array then if we do have tasks we want to prepare unassigned stage tasks the unassigned ones are these ones right here on the first line and I can notice that our app is broken now and that's because we didn't import react from react there we go we're back so if we do have the tasks let's say const unassigned stage is equal to tasks. dat. filter where we get the task and then check if the task. stage ID is equal to null so only if it's null then we know that it is a task belonging to an assigned stage finally we want to group those tasks together by creating cons grouped which is going to be of a type task stage coming from graph qu schemas array which is equal to stages. data map where we get each individual stage and then automatically return this the spread of the stage and once again with the automatic return make sure to put parentheses here and then an object we're returning then we want to spread all of the tasks. dat. filter where we get each individual task and we filter out the ones task. stage ID do2 string is triple equal to stage. ID finally we want to return unassigned stage as well as columns which are going to be grouped and don't worry about this warning right here we're going to look into that very soon but the most important thing right now is that we have our task stages we can use that directly within our Canin column so let's pass a couple of props to it let's pass the ID and this one is going to be just static it's always going to be unassigned the title is also going to be unassigned the count of the tasks is going to be task stages do unassigned stage do length or we can Define it as zero and we also want to add the on ADD click so if we want to add the item to this specific stage in that case we can call a callback function with the handle add card function and this function we have to Define right here at the top const handle add card to that specific stage and it's going to accept a property of an object that has a stage ID in this case equal to an assigned of course we have to Define that stage right here by defining the arguments as an object with Stage ID is of a type string great now you can notice that our canaban column is complaining because in it we didn't yet Define any props that it's getting besides children so now might be the best time to do it let's put this in a new line and let's define all of these new props that it will now be getting such as the ID title description count and data we can do it like so and we also need to provide additional props of types to this canvin column Now by defining a type of props or an interface either way with an ID of a type string with a title of a type string with a description which is going to be optional of a type react. react node of the count which is going to be of a type number data which is going to be optional and it will be a use droppable arguments of data coming from D andd kit and on ADD click which is a function that accepts args which are simply an ID of a type string and this function doesn't return anything so we can say void so after the data we can also add the on ADD click now let's put these props to use right here we can specify a real ID by saying ID is ID coming from the props and data is equal to data coming from the props as well so we can put even this in one line then we need to fix this typo right here by adding a column right here similarly I have defined the title already somewhere oh there we go now we don't need these fake ones we're just using the ones coming from the props so if I do this and save it that's already much better now it knows that we have some kind of a droppable Zone and onad click Handler here we can simply call The onad Click function and then call it optionally with the ID property provided like so and with that our column is now done and we're passing all of the proper fields to it but of course we're now rendering just a single unassigned column and we're not yet displaying any tasks we just have this fake canbin item right here so so what do you say that they delete this fake canbat item and this fake second column and just focus on displaying real data within our unassigned column we can do that by showing the list of tasks in the unassigned stage by saying task stages do unassigned stage map where we get each individual task and for each one we return a can ban item like so this Canan item needs to accept a key because we're mapping over it of task ID the ID that's going to be task. ID and finally it also needs to accept data that's going to be an object where we spread the task and provided a stage ID of unassigned and there we could return something like task. tile at least for now so if I save this we cannot see anything yet but let's quickly dive into the Canan item and let's make use of the props we're passing to it such as specifying the ID of the type ID coming through props and similar thing for the data now we're passing everything properly but it looks like it's complaining a bit about this ID being passed it's saying that base key or undefined is not assignable to type string that's because maybe doesn't know what this task is we're sure that it has an ID and we can easily fix this by providing a specific type to the documents coming back from our list so for our first list we can define a type of task stage like this and for the second one we can define a type of get fields from list and then expand it with the tasks query like this now if we save it it looks like adding this unassigned task actually broke the app and I think that's because in our Canan item when using the two string and if we open up the inspect element and then the console right here we can see that it's complaining about reading the two string property in the list so if I go back to the list and if I find this two string looks like we definitely have to provide a question mark right here so it doesn't break there we go so now it knows that there is one unassigned task so now that we have added that it works we can see one but why are we not seeing anything being shown right here in our column well now that we're actually getting back to data and we can see this badge what do you say that we start focusing on creating this great looking task card and to do it we can go to our components tasks Canan and then create a new card. TSX where we can run a new rafc and call it project card now we can go back here and instead of just rendering the title we can render the full project card component like so it will be a self-closing component but to it we can pass some exciting stuff such as we can spread the entire task data we want to render as well as give it a due date equal to task. do date or undefined so now we can dive into this project card accept all of these props and make it show on our screen we have passed a few props such as the ID the title the due date and some cards might even have users but the unassigned definitely won't have any but it's good to Define them up front and these are going to be the project card props and we can immediately just Define that type right here at the top type project project card props which is going to have an ID of string so we can Define it like this a title of string as well updated at of string due date which can be optional so let's do due date optional of type string let's then add the users which is optional because unassign doesn't have users they're going to have ID of string name of string and Avatar URL which is optional which is going to be a user coming from graphical schema types Avatar URL type and we can have an array of users because we're going to support multiple so with this in mind we're now accepting all of these props and we can try to render a card but how can we start rendering it if we cannot even see this div with a simple text well let's dive into the canbin item for a sec and let's try to render the children outside of this active ID if I save it you can see that still nothing is showing even though there should be one task at least but how can we even start creating the structure of the card if we cannot see even a simple text of project card I think this task that I created disappeared or somebody else assigned it somewhere else so I'm just going to do that once again and you'll also have access to this link to the deployed website either in the description or in the read me so you'll be able to add it here in the finished version and it should automatically appear for you here as well so now if we go to our list and in the Canan item we can try rendering the children right below this check and then show it here that way you'll be able to see the project card and this is exactly how I want to leave it for now just so we can see what we're doing there we go now we can even kind of drag and drop it in the dragable area works as well although we don't have any other columns so now if we go back to our project card we can start developing it we're going to use a very interesting component coming from ad design called config provider this will allow us to make some modifications to the way we're showing the card changing the theme such as colors and more so let's give it a theme which is equal to components inside of which we have components and we want to modify the tag by giving it a colar text of and now bear with me we want to define a token these are design tokens coming from hand design we can do them right here above the return by saying const token is equal to theme. use token like so but this theme of course has to be imported from ATD and then we can say something like token Dot color text secondary we can also modify the card by defining the Heather BG to be transparent now within this confing provider we can render our card which we can import from Ant design there we go now we can see our card and it actually looks very nice when you can drag and drop it this card will have a few props such as a size of small it will have a title equal to we're going to render a text property right here and this text will be coming from our components it will render a title if the title is too long we can give it an alpis so we can say Ellipsis with a tool tab of title so in case we cannot show it full we're just going to show it within a tool TP below our title we can give it an onclick property and if we click click on a specific tag we want to be able to edit it so we can create a new edit function cost edit which for now can be just an empty callback function and we'll be calling it right here on click edit later on we're going to also provide it some additional parameters then we also want to give it some extra properties which we can Define like this extra and we can give it a drop down like so coming from Ant D it's going to to have a trigger property equal to an array of click it will have a menu that it has to render with the items equal to drop down items now this is something that we have to Define so let's scroll a bit up and let's define const dropdown items we're going to use the use memo coming from react as we don't want to render them when we don't have to and and inside of it we can Define the drop-down items const dropdown items of a type menu props coming from and design specifically items right here which is going to be equal to an array of those items that we want to provide of course let's ensure that we have imported use memo and let's also give it a dependency array that is empty now these items are going to look like this we're going to have two the first one will have a label of view card so of course we can open up the full card it can have a key of one and an icon of I outlined like this which is of course just a simple icon from add design icons it will also have an onclick property that will allow us to call a callback function where we can edit those tasks and of course we're going to provide additional properties to the edit later on then we can render the second one where the danger is set to true so this is a red one with a label of delete card a key of A String of two and then onclick where we can later on delete that card so that looks like this and of course it's not an object rather it's just a function call there we go so now if you save it we can see that we are almost there but we're not yet returning the items so we can return the drop- down items and that's going to memorize them now we do have an error so if we inspect it and go to console we can see that the error happens right here react children can only receive one child element this could be happening due to drop downs maybe it's because we haven't provided any buttons or anything within the drop down so let's try to provide a single button which can be imported from ad design and this fixes it there we go right here which will act as the drop down this right here is what we're creating this drop down that allows you to view and delete a card so this button will be a simple self-closing button because we can provide everything as props it will have a type equal to text a shape equal to Circle and most importantly an icon that's going to be more outlined more outlined like this and we of course have to import it from add design icons so let's do that right away and we can give it a style of transform where we can rotate it 90° and that's going to look like this also if we click this we don't want to click at the card at the same time to drag and drop it which is an interesting lesson on its own we can give it a property of on pointer down and here we get the event The Click event and we can stop the propagation so e. stop propagation so once we point it down nothing else is going to happen the only thing that will is we're going to click this button similarly on click we want to do the same thing so onclick stop propagation and of course we have to close this one right here and this one right here and I believe this one is extra there we go so now when I click it it will just open up this thing right here and nothing else it won't try to drag and drop a card also I think we're missing an icon for the leete card so let's scroll a bit up and here in the drop- down items below the key we can give it an icon of delete outlined which we can import and render right here of course we have to add a comma after it there we go this is more like it so now our card is starting to look great here below the menu we can also Define the placement of where it will open which will be bottom and we can Define the arrow of point at Center of true so now if we go here click it it's going to open it right below this card next right where we end the drop down and we can also close it so it's easier to see we go within the card itself and in the card we want to render a div this div will have a style property equal to display of of flex we also want to give it a flex wrap of wrap just a single P there we also want to give it an align items of Center as well as a gap of eight pixels to create some space now right within this div we want to render a special SVG which is going to be just this little icon with these three lines right here so what we can do is go to source and then component and create a new file called text- ion. TSX where we can run RFC rename it to text icon in Pascal case and as a matter of fact this entire file will be provided for you in the read me down below just search for text icon and paste it the reason why I provided it to you is because it's a single SVG which we simply export as the icon component so so now going back we can import text icon coming from components text icon we can self close it and we can give it a style of margin right of about four pixels to create the space for the text that's coming after this little icon is what we have done right now now right next to this icon we want to show whether we have a deadline here we're going to play a lot with the colors of this due soon whereas if it's coming soon it's going to be yellow else if we still have some time it's just going to be regular black so right next to this text icon or rather just below it let's check if we have something known as due date options this is a variable or an object that we will create that will help us figure out which colors we want to add so we can say const due date options which we can memorize so we can say use memo and we can change the memo if only the due date changes like this of course within the dependency array here we can check if we don't have a due date then we can return null else if we have a date we can wrap it in a day JS instance like this and then we can return an object containing the color by calling the get date color from utilities and passing an object including our current due date as string for tab script and a text of date. format mmm DD now based off of these due date options we can render our tag which is going to look like this it is a single tag which can be imported from and design of course and we're going to give it an icon this icon is going to be just a simple clock Circle outlined and if we save it and import it let's see yep it is imported but we don't see it yet it's possible that's because this task doesn't have any due dates so if we go to the finished website and apply a due date here to this task like 18th there we go it got added so now in the current version we can actually see the clock so you can also go to the deployed website and play with the database there considering we don't yet have the functionality to modify these pieces of data this icon can have a style of font size of 12 pixels we can also style the tag further right here by giving it a style of padding something like let's do zero and four pixels on left and right let's give it a margin inline end of zero so we don't want to have any end margin and most importantly let's change the background color by checking the due date options. color if it's default like this default then we want to give it transparent else we want to set it as unset because it's going to be set by the options themselves then below the Styles we can mod ify the color to be equal to Due dat options. color and we can modify the bordered to be equal to Due Date options. color if it's not equal to default so if it's not it will be bordered else it will so if it has a color it will have a border else it won't have one like we have done right here and within the tag we can simply render the due dat options. text there we go this is more more like it let's also modify this test to say something more interesting like finalize canbin board that's more like it so if we go back again the realtime functionality works wonderfully and we are getting there now right next to this on the right side we want to show our users like this so let's go below our tag still within this div and let's say if no no users question mark do length so in this case we're checking if there are any users and if there are we can render a space to just provide some extra spacing coming from antd and within it we can map over the users so we can say users. map where we get a specific user and for each one we return a tool tip or we wrap rather with a tooltip which we have to import from andd but what do we wrap well we wrap a custom avatar component which we have created before this custom avatar accepts a name of user.name as well as a source of user. Avatar URL so now if we save it we still cannot see anything because we don't have any users for this task but if I go here and I add some for example let's add Michael Scott and save there we go you can see it right here now let's also modify this tool tip by giving it a key since we're mapping over it of user. ID and a title of user.name so now if we hover over it you can see Michael Scott and let's put it to the right side by styling the space with a size of four a WRA property direction is going to be set to horizontal a line will be set to Center and style will be of display Flex justify content will be set to flex end margin left will be set to Auto and margin right will be set to zero and that's going to move it to the right side and that my people is your card a more complicated card that later on will allow us to do all sorts of great things and show it in many different places we're not developing just one card we're developing hundreds of them we're just going to reuse them across all the different stages now since we'll be showing so many cards it's important to memorize the card to render only on certain conditions if all of the props of the project card component are the same as in the previous rendered then the project card component should not be rendered this is very useful when the parent component is re-rendered but the props of the project card components are not changed so let me show you how to memorize a component we can do that right here at the bottom by saying export con project card memo is equal to memo which we can import from react we pass the project card to it and then we pass a callback function of prev and next these are the previous and next props that we pass to our component and then we can return the change of these props so we need to compare them if prev that ID is triple equal to the next ID and prev that title is equal to the next title and prev due date is equal to next due date and prev that users we can look into the length of the user is equal to next. users. length and finally we can look into the updated ad so prev do updated ad is triple equal to next. updated ad if that is the case then we're going to show a new card if that is not the case meaning if something like this changed then we're going to show a new card else we're going to always show the memorized version of the card which is going to make our Canan so much more optimized because we don't want to do the unnecessary renders of all of these cards when their parent elements change but if they haven't changed themselves so with that said going back to the list we can now use the project card memo instead of the regular project card it works exactly the same but it's more optimized so with that said what do you say that we show so many more cards and stages at this point now that our card has been fully developed let's do it just after we add this plus button or we can even add this add new card if we absolutely have no cards under unassigned so let's go below this canaban item and right here below these three parentheses and we can say if no task stages do unassigned stage. length then we can display the Canan add card button which we don't have yet but we'll create soon and it will accept the onclick which is going to have a callback function of handle add card with a stage ID of unassigned let's see if this is how we should be doing that yep stage ID in this case un assigned so now let's create this Canan ad card button by going to components tasks Canan and then we can call it add- card- button. TSX we can run rafc rename it to Canan and add card button and you can find the code for this one in the read me down below as it's just a simple button nothing special happening here so simply copy it and then paste it and then going back import it from components this will bring us back to where we were but it looks like it's not loading so let's go back to our Canon ad card and let's make sure that the text is imported from the right place so right here you can import text from components text and that should be good now if you reload and go back to tasks you can see the add new card button which later on we're going to make work but for now don't forget what our main mission is and that is to show all of the cards across all of the stages so to do that we can exit our first canand column render the rest of the columns by rendering task stages do columns. map we can add a question mark here to ensure we have them and then for each column we can render can you guess what a Canan column component right here and we can pass to it a key since we're mapping over it of column. ID we can pass to it the ID of column ID we can give it a title of column title a count of column. tasks. length and we can give it on ADD click which is going to handle add card by stage ID of column. ID if you save it you can now see all of the columns appear right here with the respective numbers of tasks within each column now within it we want to check if we're loading so for that we can check right here at the Top by saying const is loading is equal to either is loading stages or is loading tasks and then if is loading we can render the page skeleton which is going to look like this return page skeleton and this page skeleton we can Define right here at the bottom below the export where we can say const page skeleton is equal to it's just going to be a typical react function where we can Define the column count to something like six and the item count as well or the card count which is going to be equal to four then we can return everything as we usually would with our Canan a canbin board container and inside of it we can marck all of the stages as well as the cards so a ray. from we can mark the length based off of the column length or the column count and then we can immediately map over it again where we get each individual index of the card within the column so we can get the index and for each index we return a Canen column skeleton like this with a key equal to index and with within it we once again take the array from but this time length is the item count or the card count instead of the count of columns we map over it again get the index and immediately return a project card skeleton coming from components to which we can provide a key of index and we don't have to say return here because I use the automatic return right here or the immediate return with a parentheses now if you reload you saw for a split second that we had this nice loading if your internet connection was slower you would be able to see how they nicely load both the columns and the items within the columns so now let's go within the second Canin column or rather within all of the columns we'll have in the future and we can say if not is loading then we can map over the tasks within that column by calling the column. tasks. map where we get each individual task and for each one we return a can ban item like this this can ban item will render a project card memo the same way that it did before so let's render a project card memo where we spread the task and render the due date and the Canan item will also have a key of item. ID since We're looping over it or in this case task. ID and the ID of task. ID as well and the data for each task off task and I do think we have a couple of these too many so if we fix it we immediately get all of the tasks back which is exactly what we wanted this entire time this is amazing all of the tasks from our database that we can see here on the deployed version are also now right here in our existing application and the drag and drop is almost working you can see that it can notice once you actually pick it up and it's going to notice the dragable Zone once you move it over which is amazing but for now it doesn't do it quite yet we're going to implement that very soon but the most important part is that we're officially fetching the data for the tasks and displaying it within the columns now if if a column doesn't have any tasks we want to show similar thing that we showed in the unassigned so let's copy this canbin add card button and go a bit below below the is loading and then say if no column. tasks. length in that case we just want to return a Canon ad card button and the stage is going to be a column. ID so now if we don't have it you'll be able to add it within the one that doesn't have any tasks and finally this task list page also will accept children yep the list will accept the children as well and we can Define the type of react. propop with children and what will those children be well let me tell you about it we're going to put it right here below the Canon so it's outside of the entire board but it's going to show on top of the screen so it's a model any kind of model that will show once we do any action like this action right here or this one right here so it's the additional functionalities to our Canen board now with that said let's figure out why do we have these lines right here whereas in the finished website there's no lines in between the columns and let's figure out those small inconsistencies that we have before we can actually start moving the data across and syncing it with the real database all right issue will most likely be within the canbin column so if we go right here and go to our div there we go this is the div wrapping it we can see that I set scroll right here for overflow Y and this does seem like a scrolling div or like a scrolling container so instead of scroll I'm going to make it auto and by itself that automatically fixes the issue so now that the UI part is done let's go ahead and expand our browser and admire our work in its full Glory we have our dashboard we have the companies the tasks and hey you can actually drag and drop stuff around it's not easy to do drag and drop features but DND kit or drag and drop kit definitely helped us although we're not quite there yet we're not fully finished even though the uiux for the list is done now we have to implement the functionality of once we actually drop it for it to stay there and to update into database and we have to do the models for the add a new car as well as to show our task details once we actually click on it so let's first make it so that once we drag and drop it it actually stays there to do that we can figure out where the drag and dropping functionality is actually happening in the card we have this part right here where we have have clicks this is only for this little thing once we click on it the view and delete we can deal with those later but for now the most important part is moving it between different elements and to do that we can go back to the list and in the list we can create a special function called const handle on drag end meaning what's going to happen after we finish the drag and drop and here we're going to get the event and we can Define the event as drag end event coming from DND core there we go now let's figure out what goes into this function this function will update task stage when the task is dragg and dropped so first we have to figure out the stage ID of the task on which the task is dropped we can do that by saying let stage ID is equal to event. over question mark. ID as undefined or string or null we have to do this types tangle right here just Ure that typescript is good to us and then we can also get the task ID of the task that is being dragged so we can say cons task ID is equal to event. active. ID as string then we can get the stage ID of the task that is being dragged so we can say const task stage ID is equal to event. active data. current question mark. stage ID so we know where it's going to then if the task stage ID is triple equal to the stage ID we simply exit out of the function because nothing happened else if stage ID is equal to unassigned then we're going to modify the stage ID to be equal to null because that's how it works for unassigned stages or and assigned tasks and finally if we actually want to move it we're going to use another refine function called update task or in this case use update which is going to perform a mutation so we can do this right at the top we can define a new hook const that's going to give us access to the mutate function which we can rename as update task because that is the specific mutation we're doing and then we can make a hook call to use update that's coming from refine Dev core and we just call it as a function that's it it will automatically provide you a specific mutation function which we rename to as update task that's going to do everything we needed to do so right here within our handle on drag end we can out call the update task and provide it an object of options first of all folder resource we're talking about or moving in this case tasks then specify the ID of the record that should be updated so we can say ID of task ID then specify the values that should be updated and the values is going to be the stage ID so we are updating the stage ID to Stage ID of the ID that we are moving or of the task that we are moving I hope that makes sense then in this case we can disable the success notification by saying just false because it's a simple drag and drop and then mutation mode as we discussed before in this case can be set to optimistic that's interesting before we used pessimistic I believe here we can use an optimistic one so let's say optimistic and we're doing that to make our app seem more performant because then the change will happen automatically and it's going to move it before it actually updates it in the database which is necessary for good user experience but we're going to assume that the database update will happen as well which it most likely will finally since we're using graphql we can provide the last property which is the meta property defining the specific gql not query but rather gql mutation of update uncore task uncore stage uncore mutation which we of course have to import from graph field mutations and let's quickly look into it it simply takes the input which are everything we need for a specific task in this case just the ID and it calls the update function and Returns the updated ID so we have the update task which now will be happening at the end of the handle on drag end so let's see where we can call our handle drag end we're going to call it right here or not call it rather pass it to our Canen board so we can say on drag end is equal to handle on drag end we can go into the Canan board and right at the top alongside children we can also accept on drag end and we can also Define the props right here by saying props and we can say type props is equal to it's going to accept the on drag end function which is going to look like this it accepts an event which is of a type drag event or drag end event thankfully DND kit core provide that for us and it doesn't return anything so it's void now finally we can use it or pass it right to our DND context this is the most important component or wer or context whatever you wish that manages our entire drag and drop process so right here we can give it the on drag and property and we can pass the handle drag and function which we are passing through props so it's not on drag end I believe it should be handle drag end let me look into that can bend oh I passed it into the can bend board container whereas I should have been passing it into the can bend board yep you see that right here on drag and coming to canvin board not the container so so let's remove it from the Canan container and just put it right here directly on the canbin board so if I scroll down I'm going to define the type props right here get it here on drag end and now we can also Define the props and we can simply call on drag end on the on drag end within the DND context great now another thing we want to pass to our DND context to make it work flawlessly is something known as sensors we can say sensors is equal to sensors and now we have to Define it at the top by using the sensors hook let me show you how that works right at the top of now we have to be careful it's going to be canand board not canand container there we go so right here we can say const mouse sensor is equal to use sensor coming from DND kit core and it the first parameter is going to be the mouse sensor coming from DND kit core and then we can provide additional options in form of an object the only option we want to provide right here and don't worry that the app is breaking right now we're going to fix it we want to provide something known as an activation constraint with the distance of five now what this does is it's a property that we can use to specify the condition under which a draggable item becomes active or in simple words when are we actually dragging it so this is five pixels which is the minimal amount we need to drag it by to actually consider it as a drag and we can do a similar thing with the touch sensor if we are in mobile devices keep in mind we want to make our app fully mobile responsive so let's also Define the touch sensor which we can do right here below const touch sensor is equal to use sensor in this case we provide the touch sensor to it coming from dndd kit core and we also provide absolutely the same activation constraint you can play with that a bit you can also give it some delay or tolerance or just different things to make it work better on mobile devices but in this case I'm just going to provide it a I like how chat GPT filled this out as dinosaur uh not sure why I did that it's just a distance of five pixels right here now that we have our two sensors Mouse and touch sensor we can simply provide them as sensors right here con sensors is equal to use sensors and now we can pass all of them together Mouse sensor and touch sensor and it this case you notice that this is use sensor singular but this one is the use sensors plural to which we pass already defined sensors now our drag and drop functionalities are going to be even more precise so with that said the sensors are done the on drag end is done so let's see what happens if I move one task from Todo to in progress and before I do that I'm just going to make this a bit larger larger so we can see what's happening and drag and drop there we go it moved in real time now just to ensure that it actually worked let me reload the page and you can see that it's still there let's try to move everything from to do to in progress let's say we want to have a really productive day today you can see the label updates in real time the tasks move in real time and we can move everything so seamlessly between different things this is amazing now I notied that if I try to move it to unassigned I do have an error invalid input Syntax for type integer unassigned this is an interesting one it's coming from the on drag end function which I think is in the list so if I go here to update task apparently it doesn't really like the null part let's see why that is I just noticed that I passed two NS right here instead of one so if I say unassigned like this properly how it should be spelled then it's going to reset the stage ID to null which should make it work with the unassigned column so if I now move it nope it's still the same thing let me reload the page just to be sure un assigned and if I move it nope still the same thing we can still see that it's showing a double n right here so let's copy it and let's search our code base for a double n i paste it and looks like I did call it un assigned with a double n a couple of times right here and a quick Google search will immediately let me know that that's not the correct way to spell it so going back we might need to fix those I mean the variables are fine because we're just using them here but if we're doing this properly let's do it properly I'm going to fix the spelling in all cases right here unassigned unassigned stage right here and let's see we have a couple more instances this one is the most important one we have the ID and then everywhere where we use the task stages this has to be unassigned stage spelled properly and also here on ADD click this is important the stage ID is unassigned let's also do it here we could have done this automatically using contrl F but this is good as well now just one final instance which is this unassigned and we are good now let's see what's going to happen if I try to move it around to unassigned we still get an unassigned integer right here invalid input so first of all I think that when I was trying to modify it to have a single n i mistaken remove One S as well so now let's use this automatic update to show you how I can easily change this I'm going to turn on both the match case as well as match hole word or no we can we can just use this one and then I'm going to modify the unassigned to include a double and then replace all instances right here this should be good so now everything says un assigned properly and immediately this fixed an issue on its own we can now also move to unassigned as well as all of the other columns this is great and with that our our list is almost done we can also click here and then view card that's coming soon or delete card which is also coming soon but what else do we have here with our list is there something else that we should be showing or doing well while we're here let's Implement these two functionalities The View card and the Elite Card those are going to be within our card so let's go into our card and right here under drop- down items remember that we didn't yet complete these functionalities the edit or the onclick on both of these so let's first focus on the edit function that we have here and edit will be coming directly from Ed navigation it's a hook from refine that allows us to navigate to a specific page and edit navigates to the edit page of that specified resource it's so simple so here we can say const we can get the edit directly by using the use navigation hook use navigation coming from not react router Dom but rather refine Dev core there we go and now we can pass those additional things to the edit right here on The View card why are we using edit if you're viewing it well that's because we're going to both view it and edit it on the same model so right here we can say edit tasks provide the ID which want of view or edit and then say replace right here for the history type because it's a model so we don't need to go back once you click back this is it for the view card and then for the delete it's even easier we can use a new hook const mutate which we can rename as delete and that's going to be equal to a call of use delete from refine Dev core there we go and now we can simply call on click right here we can call delete within this function block and we can pass it an object of resource is tasks ID to know which one we want to delete and The Meta of operation is set to task so it's an automatic operation to delete but I just noticed that delete might not be the best name to call it because it's a predefined keyword of the JavaScript language so I'm just going to leave it as mutate right right here and then call it mutate down below as well there we go so now if we try to delete let's say Implement security enhancements we can click delete card and right up the bat everything just works this is what I like to see I know it took some time to set up the foundations of everything and to set up the structure of the project but now that everything just works seamlessly by simply calling a hook it's pretty crazy to see it that way complete crud functionalities working right out of the box now the view is almost there but not quite yet it redirects to edit 8 and we have to fix this within our router because soon enough we're going to navigate to a different URL but it will still be the same page because it's just a model that's going to show on top of our list and a pretty cool thing is that this Details page of each task is is at the same time the edit technically you can think of this as a form where you change a couple of selects to-dos and even some markdown modify the due date and change the people you can also delete card there so we're going to do that very soon but already I like what I'm seeing here we can move it around and let's not forget before we move ahead to the details and edit so right now on the deployed version this is how it looks like a new form that has the title and if we click here nothing happens so let's figure out where we have this add button it should be under each column so if we go to the column and if we search for on ADD click Handler it looks like we do call this onad click Handler which is coming from our list so we need to move to the list to be able to see what this function does and now if we see the handle at card which we're referring to right now it's not doing absolutely anything so let's make it do some work right here what we can do is say const path is equal to and we figure out where we need to redirect to so to get this path we can say args which will include our stage ID so we can say do stage ID if it's equal to un assigned like this unassigned then want to point out to SL tasks slne but if it's not unassigned then we want to point to for/ tasks for slne with a query parameter of stage ID equal to and we can make it a template string as well so let's do that and here we can feeded the ARs do stage ID finally we want to use replace coming from refine and react router Dom to modify the path so going at the top right here we can use a new hook const replace where we get it is equal to use navigation coming from refine Dev core and then we can use this replace to replace the path once we want to add a new card so now if I go here and if I click new it's going to point us to the task new and at this point in time neither the task new or the task edit and then a specific number exist they are nowhere to be found so what do you say that we closed all of our files and navigate over to app. TSX and implement the last two remaining routes of our application it's actually going to be a bit different from what we had with the companies companies did have some routing and they did have additional Pages for the edit but here for the task everything is going to be within one page it's just the URL that's going to change so we can Define one route and we can automatically provide the element of list on that same route because it will be showing on all the routes so right now that looks something like this route path of tasks which renders the element of list and now we can use a special component within it which is called Outlet that looks something like this this is not a refine feature it's just a react router Dom feature and Outlet allows us to render the child routes inside of the current route but I just noticed that I didn't follow on the syntax correctly if we're going to make this work we have to actually expand the list to accept children elements and then we can add Outlet to it as a child so let's put this in a new line like so there we go and now we put Outlet here as a child if you remember correctly our list did in fact accept children and we are rendering them right here at the bottom so what react router Dom will do now is it will figure out whatever we pass in this route and it will add it to the outlet so how do we do that well we can simply add two new routes route of a path new keep in mind we're still within the parent route of tasks so this is tasks new where we add a new element which is equal to tasks create page and this is something we'll have to create and we close it once again finally we can duplicate it as well right below and this is going to be edit forward slash and then ID and this is going to be tasks edit page there we go so now let's create those two we can do that by going to Pages this time then go to tasks and then create a create. TSX run rafc and there simply call it create task and also create another one which is going to be called edit. DSX run rafc and call it edit task now go back within the app and rename these two create task and edit task and make sure to import them from Pages tasks edit and Pages tasks create now if we save this you're going to notice that even on tasks edit you'll still be able to see the list but then we can show something else on that new page such as there we go at the bottom we can see edit task but of course we don't want to show it on the bottom we want going to show it as a modal overlay which we're going to do pretty soon so for now let's just expand this and look at that we can see all the different columns we can move stuff in real time and keep in mind if you have somebody else working on this in real time with you they'll be able to see the changes live on their computer we can move things around we can even delete cards we can create new cards not yet but soon and it's all just working so seamlessly we have the dashboard let's not forget what we have done there we have the companies as well with complete edit functionalities with contacts it's just looking so great but now there's one last step and that is to make that details sledit model and believe it or not it doesn't do anything that we haven't yet done so far this model is going to be almost exactly the same as the form we have created for create a company or even more similar for the edit a company that we have right here so what we can do is simply go right here to tasks we can collapse our browser and move over to create task since we've already used all of the hooks such as the navigation use list and use model form I'm going to Simply provide you the complete create task file which you can find in the read me below so copy it and paste it right here and the only thing I'm going to do to it is I'm just going to make it from the named import or export to the default so we can say export default tasks create page this might have been already done for you at the time of copying it and now if you click plus right here you can notice a new card appear and if we type test and click save it's just going to work right right off the bat but now how do we add additional functionalities to this test such as added a date due date assignes and more well let's move over to the edit task which once again uses absolutely the same Hooks and functionalities you've used before in the create company or edit a company model so in the read me down below you can find the complete edit task file copy it and paste right here some of the most important details right here include the fact that we're using a model and then passing all of the most important model props coming from the use model form exactly as we have done before now you can see that we also need a couple of components to make it work and to get to those components you can download the zipped form folder from the read me below unzip it and then paste it right here within your components and then tasks next to to the Canan it should look something like this where you get all of these right here since we copied them we'll also have to modify our index. TSX or TS so we can automatically export them so there you can add something that looks like this export everything from do/ tasks form description and then we repeat that for due date stage title users and headers and this will allow us to just import them all automatically within a single line or in this case m multiple lines and the last missing piece is the accordion so going back right here we need to also make sure to export that accordion by saying export everything from that's going to be slash I believe accordion is right here in the components so that's the last component that we need create one last file of accordion within components folder. TSX copy it from the read me down below and and paste it right here and finally in it modify this text import by removing it and automatically importing it from SL text so now if we go back all of the exports are good all of the Imports within the edit are good and if we reload we would have hoped something would have worked but in this case it looks like we have an error regarding our MD editor the MD editor stands for markdown editor and that's happening in our description. TSX where we're trying to import this component which will allow us to modify the markdown description of our tasks of course to make it work we just have to install this package so open up the terminal type mpm install and then you can paste that add UIW react md- editor as soon as it is installed the error should be gone so let's reload the Page open up the console or the inspect and it looks like we have an unod error with an export of text which is happening in the title so if we go to our title yeah it's always that text so it might be just a good idea to properly export it from here I'm going to say export everything from slash text and then we can do it like this that way it should actually be within the components so now it can find it either way so if I reload this now the text is good but it's having trouble finding the user tag as well so let's look into our index and we might need to export the user tag as well by running export everything from and here we can say slash tags slash user- tag and this is the last component I believe which we haven't yet created so let's go to our components tags and create a user- tag. TSX file and at this point you know the drill this is a simple component so you can find it in the read me down below paste it and save it and it looks like this file has a problem with the custom avatar so let's remove this import and let's just automatically import it by double clicking and then pressing control space and getting it from do custom avatar this was the default export so now we're doing it properly let's reload and it looks like we have to go to the edit. TSX right now of the tasks as that's also the named import so once again usually whenever you have a convention like doing the named Imports or exports or default imports and exports just make sure to to stick with one in the case of this video we have been kind of mixing them around and you can see that it's not the best practice so you can learn from me in this case um but what we need to do now and you can see it right here I'm really glad we're getting a chance to debug through all of these issues is you can go to the app. TSX line 23 so similarly what we have done with the create we've just reverted it back to the default we can do the same with the edit so right here if I go over to the edit task I can remove this export const at the top and just make it export default tasks edit page at the bottom export default tasks edit page with that we can reload and finally we are back to our list I know this was quite interesting to fix all of these issues but hey we have done it uh and I'm glad we're able to go through this debugging process together maybe you even caught some of the issues or bugs before I did in which case great job so let's now close all of the currently open files and let's simply expand our browser with the addition of these new components we've added now the add new card should be there we have tested that already but just let's test it once again by saying something like finish my grade dashboard and save this indeed does work but not now the moment of truth is if I go here and if I press view card it actually opens it up or could we make it so that I can actually click it that would be interesting because right now I can just drag and drop them well back in our card. TSX in one place we used this stop propagation thing which was right here in the drop down I believe there we go we stopped the propagation but only on the button now now let's see if we can do the other way around right here if we click the text we should be able to navigate to the details so if I scroll a bit up right under items we can also add the on pointer down which is going to be set to a callback function where we get the event and we can stop the propagation so we can say e. stop propagation and also on click so right here on click we can also pass an event or rather get an event that we clicked on and say E.D event. stop propagation so now if we do it this part is working a bit better but the title is still not clickable so what we can do is modify this on click right here within the card and it's using the edit and remember what edit is edit is coming directly through used navigation so we can simply say edit or go to the edit of tasks for this specific ID and replace the current URL so if we save this it will actually open up the edit so now if we're not drag and dropping it it will be completely clickable and it will open up the complete form where Let's test it let's try to finish this great dashboard by selecting a stage let's add it to in review for now let's add a description we have a complete markdown description right here where you can say something like bullet points and you can say implemented and then we can open up bullet points like dashboard we can also add companies and tasks and you can press save that's great we can mark it as complete we can add a due date let's say that it is today make sure to press okay and press save and we can assign this to our current user which is the admin user now if you look at this card it should have automatically been moved right here to in review and I think it's safe to say that we can drag it over to finish my great dashboard as done this is it it definitely took some time but I believe this was a phenomenal learning experience for all of these live features the can been board the dashboards and and companies and tables and even more stuff it's so crazy to see that the Canan is actually just a part of the dashboard whereas usually it is a complete separate application like jira or Trello and here you have it you have just implemented it as yet another route so finally it's time to get our project live and in front of other people and to do that we'll deploy it on the internet so hey head over to GitHub press this plus and create a new repository give it a name something like refine uncore dashboard in this case we'll do and make it either public or private in this case I'm going to leave it as public and press create repository next we can put this side by side by our codebase and we can open up our terminal delete this one and stop the other one from running we can clear it as well and we can just follow the commands to get our project deployed that is get init git add dot git commit dasm initial commit then we can copy a few of from here git Branch m- main get remote at origin and get push U origin main just like that if we now expand our browser you'll be able to see all of the code you've been working so hard to create there we go it's right here now that we have our code deployed let's head over to versel as you can see I have quite a few projects right here some of them are YouTube projects and most of them belong to our master class which is a dedicated JavaScript Mastery boot camp where we don't teach people how to develop projects we let them develop them and then provide them additional mentoring so if you want to join the link is going to be down in the description but with that said let's click add new and let's click new project versel should automatically recognize the new repo we had there we go refine dashboard and you can simply click import and that's it just click deploy it's as easy as it can be let's give it a minute until it does its thing and hopefully we'll be able to see our web application Live on the internet but it looks like not everything goes so smoothly here we have some issues with typescript which is totally okay it's a huge application and we were trying to follow typescript as close as possible but it is possible we missed a few we're only human right so what we can do here is I think the way to disable typescript on deployment on vit is to modify environment variables so let me go back to my projects and there should be a new project right here for for you as well refine dashboard go to settings go to environment variables and then add TSC as in typescript compile on error and set it to true this should allow your app to compile even if we have some small typescript errors and save it also I notied that we still have this refine thing at the top and since we're deploying our app it might be a good chance to remove it let's go back to our code specifically to the app. TSX scroll down and here we can find where we have that refine bar I think it's this one GitHub Banner we can remove it and that's going to change the bar right now our Local Host is closed which is why it's not making any changes but in deployment it will have changes and finally we have to modify a small thing with our testing Suite right here and that is within utilities date and then here DJs provided us a testing Suite but in case we just want to get our app deployed right now we can remove this testing suite and now we should have no problems with deployment so let's simply run get add dot get commit DM and let's say fix errors and then get push this push will now remove this stop bar it will also remove that test allowing us to proceed and finally it will redeploy the app on verell which will reapply the new environment very variables so let's give it a minute and see how does it go and unfortunately it looks like we still have some tab script errors right here the same ones from before so let's maybe not be so lazy and let's try to see what this is really about I think the majority of these typescript errors are within the list. TSX so if we navigate over to list. TSX I do believe it's the one regarding the company yeah so it's list. DSX for the company and here we can see values the type is unknown on search and that's because we didn't properly provide the types of what's going to be coming to this table so to do that we can do this we can open up a new typescript block and then say get fields from list and then Define the company's query or company's list query specifically and close it like here and then we also need to specify the HTTP error which looks like this coming from refine Dev core and finally one more time get fields from list we have to do it just due to the fact of how the use table works and what does it return so now if we do that it's no it will no longer complain about the values let's see if we have some other problems or was this the only thing I think this is related to tasks here so this is in the pages tasks list as well so let's navigate over to tasks list and here we have one error at the top which is right here complaining about the grouped when defining the task stage right here I think I just automatically imported it from graph kill schemas but we have to modify it a tiny bit right here so I'm going to remove that import and I'm going to right here at the top Define a type of task first of all which is equal to get fields from list and then task query we're getting the fields from the tasks query list and only then can we Define a type for the task stage right here which we do by getting fields from list but this time task stages query so task stages query there we go and we can also say and tasks is an array of individual tasks so if we do this right now we can remove this empty import which we're not using and we can now use this new task stage as the type and it's no longer complaining so we can close these two files and since we weren't lazy developers we can go back to settings and then environment variables and we can remove this environment variable which we added added which didn't work anyway so it's not like it really matters but hey we fixed it now I thought there was going to be more tab script errors considering the size of the project but thankfully we just had two so finally let's say get add get commit DM let's say fix typescript and get push versell will automatically try to recue and redeploy our deployment so let's check it out third times the charm and there we go if you click right here on this build or if you just go to the project maybe even better you'll be able to click visit to see your project deployed and live on the internet in this case we can log in as Michael Scott one more time and there we go a full complete dashboard connected to the back end greets us with the upcoming events data latest activities and even all of the company right here working in real time but the part that I'm most proud of is of course the Canen tasks board where we can move things around move them to unassigned and even create new cards not to mention the markdown updates overall the build of this app has been a huge success I know it wasn't easy but we've done it I hope you learned a lot about building big and scalable applications it's a completely different thing building a small dashboard and just making it work and then building something that has the potential to scale to hundreds of pages this is how I perceive this app it truly does have that potential because of all of the features that are exposed and provided to us by refine with that said huge thanks to refine not only for sponsoring this video but for building such an amazing open-source tool also if you came to the end of this video you are the perfect fit for our ultimate courses here we've been building everything using V but I'm sure you want to dive into the latest and greatest of what NEX gs14 offers and I'm not talking just about using nextjs like you would use react I'm talking using it to the fullest potential making sure that you get all of the outof the Box SEO benefits and learn how to use NEX GS in dep you'll go through deep dive lectures to understand how things truly work then you'll build an incredibly complex app in this case that's going to be our Dev overflow which is a complete stack Overflow clone and we'll also have active lessons that allow you to practice your knowledge in real time to ensure that you never get stuck in the tutorial hell simply go to JS mastery. proo or click the link in the description with that said once again huge thanks to you for coming to the end of this video and have a wonderful day
Info
Channel: JavaScript Mastery
Views: 393,128
Rating: undefined out of 5
Keywords: javascript, javascript mastery, js mastery, master javascript, react admin dashboard, react admin, react admin panel, admin dashboard, react tutorial, react website, react project, admin dashboard design, admin panel design, react design tutorial, react admin theme, react hooks, react ui design, react for beginners, react full course, react admin dashboard tutorial, react dashboard, react js, react kanban board, graphql, graphql react, graphql tutorial react
Id: 6a3Dz8gwjdg
Channel Id: undefined
Length: 338min 33sec (20313 seconds)
Published: Fri Jan 19 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.