Build a reading list app with React, Shadcn, Tailwind CSS, Axios, Zustand, and Beautiful-React-DnD

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so what we're going to be building today is this reading list application that lets you um manage your well your reading list so it is uh connected to a third party API and by connected I mean it connects to a third party API so just show you how that works um let's say I want to add a new book to my reading list we'll look for um one of The Chronicles of Narnia books so I hit search and as soon as I hit search you'll see it gets all the results that um come back from uh the open Library API that have Narnia somewhere in the description or the title so I'm gonna add Prince Caspian it's my list this will add it to my backlog uh or my four later list so if I come down here you'll see Prince caspan over here we're also going to be using um react uh dra beautiful Dragon drop um which is a package by atlassian to enable um a more ux friendly sorting uh experience so yeah uh um we're also going to have these lists be manageable so like let's say like you know the user's done reading The Hobbit they can come over here and they can mark this as done uh when there's nothing in the list you just have a little quote from Bren Frank Ben Franklin to encourage you to read some more so let's go ahead and do that we'll add The Fellowship of the Ring to our current reading list and then um you'll see at the bottom anything that we finished will be stored in the done um uh list which actually isn't um drag or sortable and you know you can you can change that if you want but that's kind of the ux that I thought made sense but you know I'm just a guy uh there is also the ability to delete things so you'll see um when you hit delete you'll get an HTML confirmation if I say okay it blasts it away from the list and nice thing about this is uh we don't have to worry about connecting this to a third party API or um if you're trying to put this in your portfolio which I highly recommend um you won't have to deal with AWS uh uh hosting costs or anything like that because well all of this data gets stored on the user's uh local storage and you can change that if you want you can connect it to your own um your own rest end points uh and and your own database like if you want to connect it to a superbase database I'll leave that to your discretion but for the purposes of this video I wanted to keep it short and sweet focus on UI I think um I think that's it for the uh overview so to get started head to the um Shad CN uh homepage so that's at ui. shen.com go to the docs installation choose V and then let's start running some of these commands so I am using yarn personally so I'm going to be using the yarn commands so that's yarn create V and it's going to give me some options so I'm going to name this reading list app I'm going to choose react typescript for my implementation and I'm going to go ahead and open this so I'm gonna type code reading list app and this will open it in vs code so let me actually pull that over from the side and once you get your vs code open you can go ahead and hit control Tilda that'll open up your integrated terminal um and from here let's go ahead and follow the rest of these instructions so we are going to initialize tailwind and since we are using typescript I'm going to update my ts config so we head over to RTS config and then inside of the compiler options just add a comma to this uh there we go save that and what this is going to do is this is going to let us um reference um our components from the component Library using the at Shand so the next thing we want to do is we want to install some Dev dependencies now um you can install the just the um the node types if you want but for me I like to go a little bit above and beyond and I like to install the following so we're going to run yarn add- D and then I'm just going to paste these in here so these are just some uh prettier plugins and stuff like that I personally um I like to set up my prettier uh first before anything else so just CU I I get annoyed with bad formatting and want to make sure that um that you know everything looks nice and tidy so the these are the prettier plugin tail when CSS prettier eslint plugin tail when CSS and types node so we hit enter and I am going to zoom in over here just so it's a little bit more legible um might be a little bit too much but that's okay let me just there we go okay so last thing we want to do is in uh where is this this is our V config so we hit to our V config replace that with these contents and um oh so this right here is because um my uh my vs code is expecting uh prettier but I don't have prettier so or I don't have a prettier config excuse me so let me go ahead and paste one in here um so my prettier config uh for V Tailwind apps is pretty simple so I just pasted this in here just create a prettier RC file so prettier RC and in here just um copy poast to this so you have the um the prettyer plugin tail in CSS and um I I don't like to deal with semicolons in my code so you can disable it using this and also prefer to use tabs just because it's a little bit um more uh accessibility friendly so and you can you don't have to do this you can use spaces if you want but this is just my preference um so once you have that I think the last thing is just initializing Shaden so let's go ahead and do this and I'm doing this first um because we are going to be using shaten components here I debated whether or not I wanted to go and just do like raw Tailwind um CSS but I figured you know like the the purpose of of this specific tutorial is to go through like the um the entire uh I shouldn't say the entire process but like it's to kind of show like how to um make smarter react applications meaning like react applications that are hydrated by third party data sources and so forth and so on so because there's like so much going on I didn't want to like spend six hours doing all the things that we can do in like I don't know maybe two hours so yeah that's more or less what it is and also that SI is beautiful it's a really nice uh package so well it's not a package it's an implementation um and you'll you'll learn more about that as we go so um in this prompt uh let's see I do I am using typescript um you can select what style you want to use I'm using the default but New York is just a little bit more condensed and um like everything looks is styled a little bit tighter I'm just going to be going with the Slate option and for my Global CSS I think he actually has the options here here listed for what you should do for V uh yeah there we go so this is going to be just your um base CSS which is at source SL index. CSS spell Index right yeah and then um we do want to use CSS variables for colors and we are not using a Tailwind prefix our Tailwind config that is correct um that is correct enter yes I do want a lib utils and we are not using server components because this is um vit which is a client side render and we are good to go so hit yes and it will install dependencies and everything is looking super Dapper so yarn Dev and it's running at Local Host 5173 so just all click that to open it and now we have our server running um so yeah now uh well actually let's clean some stuff up real quick so I do want to get rid of up. CSS we don't need this yep bye-bye um we do need to clear out actually actually no this is cool um it already updated our index. CSS and I think that is about it I am just going to get rid of everything in here and just do rafc just so that we start Blank Slate we save and nice we are good to go so first thing we want to do is I'm actually going to hide the um the sidebar real quick so the first thing that we're going to want to do is actually connect to the um open Library API and if you head over there um so it's just open library.org you head over to this sidebar over here this hamburger and you'll find the under developer Center you'll find there is something yeah there we go web API so click on the web API and then there's a few different apis the one that we care about is book search and that yeah there you go so you'll find all the details for the API here like what you can use what you can do all that kind of stuff um it is constantly growing so you know hopefully this tutorial has like some longevity um but in the event that something changes this is where you want to come so that you can um changeing change excuse me change things up a bit um so yeah so this is the API that we're going to be using so let's create the component that we're going to use um for searching so uh let's first add a default export so export default app and we can remove this first export keyword and then in um in my components I'm going to go ahead and create a new component called book search. TSX going to run rafc to initialize the component and this component is going to require uh so it's going to do two things um it's going to it's going to have the um input for um for the query that we're going to search again so we're going to be able to like search by author by Title by ISBN so forth and so on whatever it is that um um the open Library API will accept so we're going to say uh const quer whop query slash Set uh not slash comma set query and we're going to set this equal to use state which we will need to import from react um and we're going to initialize this as an empty string so this is going to be the query that we type into our input box the next one um actually I said we need two things we actually need three things technically so the first thing is the query the second thing is the results um actually it's not the results but the it's technically the third thing but that'll make sense in a second so um this is going to be what we use to um store the actual response that we get from the um rest API call so we're just going to say results and then set results equal to use state of type any and it's actually going to be any array and I'm saying any because well we don't have their like we don't have their types defined for their rest API so this is like a little bit of a of a hack for us and to get rid of that um to get rid of this type error that's screaming at us right now where it says unexpected any um we can just use a uh Nifty little trick if you go to eslint and um underneath in in your rules underneath the last one just add a typescript lint no explicit any um so that'll get rid of that error um so then what we want to do is add a loading state so while we're waiting for the results to come back because this is and it's technically an asynchronous call right because we're not we don't have this data we have to fetch this data in order to show it well we need to have a loading state so we're going to say const is loading set is loading equals use State and we're going to default this to false now we'll create the async function uh that is going to actually um run when we hit the search button so we're going to say const search books equals async and I am going to accept that suggestion it's going to take in no parameters and inside of here we're going to say that if there is no query so if the query is empty then return and if there is a query what we want to do first is we want to set loading to True right because right now we're about to kick off our asynchronous call with a try catch and right before we actually try we want to have our loading State set to true that way we can't keep clicking the button um while there's a call that is about to be in progress um so inside of our Tri catch we're going to say const response and this is probably a good time for you to install axios so just yarn add axios cool then you can hide your terminal again and um in here we're going to await axios so I'm going to import that up there hello that's a weird import let's try that again AOS there we go I don't know why it imported it like that the first time ax. get and we need to um we need to pass in the URL uh for the open Library request so if you head back to the open Library search API you'll see it looks kind of like this so where we have open library.org search. Json uh Q equals and then this is the query right so we're in Ed in this part so we copy that head back to the um interpolated string add that over there and then we'll open up a curly bracket so that we can pass in the query that the user um has typed in uh so let me first actually Define the type for what we're expecting um our result to be and we're going to do we're going to call this search result and we actually need to Define um this type up here so well I say type but it's actually an interface I guess we can we can just call it a type so type search result equals and this type is going to contain um docs which are going to be not a new type of any because I don't know what the return value is going to be well I know what it's going to be but um there's no way I'm going to be able to create a type for what docs represents just because it's like huge um and then and we don't need all of the things that come in DOS um there's other ways to do this it's just this is a little bit more expedient um and then we're going to say num found so this is going to be the number of results that we end up getting back um we're going to store this in here so what do we want to do now Let's uh oh we need to set the results so um once this response comes back we're going to set results to the response. dat. docs okay so we hit save and um I actually need to catch the error so if we have an error we'll say console. error so this will make your console log show up in big red color um and we'll just pass in error fetching open Library API data and then pass in the error next to it um and regardless of what happens in the tri catch right afterwards we'll set the loading state so set is loading to false so that means that whether it passes or fails loading will be set to false afterwards um so last thing we want to do is well you know what let's go ahead and start creating the the template and then we'll start adding some additional logic in here uh so inside of this template we're going to open up a I am erasing too many things we're going to open up a div with a padding of four h am I tripping today let's try that again okay there we go not weird Intellis and stuff um now inside this div we're going to have our input and our button which we actually need to import from shat again so in order to do that if you head over to the button and you go down to under installation there's the CLI command so nice thing about Shad CN is he created this nice little interface for you to be able to just make get errors in your terminal apparently try that again okay there we go so this interface is not actually installing anything from npm unless like you have a package needed from um radic UI for example this is just uh creating this component somewhere inside of my UI Library so it just created this component copied it over um and it installed whatever packages were needed for it so in that case it was the uh CVA package and the um radx UI react slot package so uh now I can actually import this button so I'll show you quickly how that looks so if we open this up type button um and actually I do want to use the Shand that we were using earlier so instead of this we're going to have the at/ components so this is what we were doing in our V config where we um defined our import Alias like so so this lets us instead of having to like type in a uh relative path every time it just lets us have at/ components so no matter where you are in your um in your repository it'll always be the same import statement um nice little trick so we'll do button and then let's also we need to import the um input component and same as before copy over the CLI command enter and um this one will actually I did this earlier um off camera but this one will require the forms plugin so if you haven't already just run um yarn add uh Dev dependency uh tail when CSS forms and I did modify the way my Tailwind config looks because I don't like the way he does it it's like module do Imports or something I don't I don't like the way that works just personal preference um this at least uh I don't have to write like require or anything like that just do it the way I'm used to doing it um I prefer the consistency so go ahead and update it like so and once you're done with your Tailwind config you can head back to the button search and we'll or the book search excuse me and we'll go ahead and import the input component it which is my CLI is being really weird not my CLI my IDE it's not defaulting to the um to the uh the import Alias but that's fine so now we have our input um I do have an error over here and that's because I didn't spell app right so if I save that now if I head back to my V application I can refresh and there we go there's our app and inside of here I'll go ahead and import the book search component and you'll see now we have a button and we have this input um so these look terrible of course but we're not going to keep it this way um this is just to show like how to import things from shaten so now that we have those imported we can actually start making them look nice um so inside of our div we're going to put this input up top and we're going to give it a type of text um it should be type of text as a string and then we're going to set its value to the query uh State value and we're going to say when it changes we're going to set the query as the event Target value so set query as e Target value and um we're going to have a placeholder where it says search for your next book and there you go there's our little input um so it I I don't want it to have it full width like this that kind of looks atrocious so we're going to just cut this at a div with a um so at the small break point so we do want to have it width when it's on mobile but once it hits the small uh screen break point we'll give it a Max width of X small paste that back in there and there you go so now it's a little bit more manageable um now underneath here we do have a button which we want to use to search for books so we'll say on click on click onclick and passing another arrow function takes in no parameters and it will run dude what let me try that again okay there we go it'll run search books save that um you know I should probably have some text in here so let's let's actually add that text um there we go and as a matter of fact we'll have it so that um if the loading state is true we'll have it say searching otherwise it'll say search save so now we can come in here and um we'll do Lord of the Rings and hit search it's searching and then I got Lord of the Rings but we have no idea what it is because we aren't displaying that anywhere so let's go ahead and fix that so underneath the button let's add a div with a margin top of four a Max height of 64 and overflow Auto and in here we'll just do a um unordered list and in this unordered list we'll pass in the results so we'll say results map and then we'll open Anonymous function with the book and the index um I don't know why I said second let's just get rid of all this place it with an open parenthesis and in here we'll pass in a list item a list item that will have a key key of in index I forget how to type whenever I'm recording myself it's awfully embarrassing inside here we'll pass in a json. string gii uh of the response so just book comma null comma to just format it a little bit nicer and if I hit save holy heck you'll see there's a lot of data over here and this is everything that came back with the Lord of the Ring search now clearly we don't want all this so we're going to have to do a little bit of cleanup but before we do that there's a little thing that's annoying me um I prefer personally when I type something in to hit enter to search and currently we have to actually click the button to search so I'm going to address that I'm going to add a function underneath search books we're going to call it const handle key prep and it's going to be an anonymous function it's going to take an event we'll just say react. key board event um and what's going to happen in here is we're going to say if event. [Music] key I meant equals and instead I hit backspace three times so if the key that is pressed is enter and you can do this for basically any key but for us we care about about enter uh we're going to say search whoa search books so when we press enter it will um it will check the key press if the key press is enter then it'll search books so now let's go down to um to our input and we'll add an on key up so you can do on key down actually but uh I don't know I I feel like I feel like it's better to do Onkey up because um on key down is like when you actually hit down but sometimes you might want to Escape you might have hit enter by accident and you want to hit Escape before you set enter so on key up just ensures that after like the keyboard the this the the enter key has come back up which is a confirmation that the user did want to do that that it actually runs so we'll say Onkey up equals and this is just preference you can do whatever you want you can do Onkey twerk and that's not a thing I'm just messing around um so we'll say handle key press here and save that and now if I come here and I write Percy Jackson and the Olympians hit enter you'll see it starts searching and one last thing is uh that button should not be clickable when it's searching so let's go ahead and fix that um and that's actually super simple inside of the button component we'll just do disabled equals true if is loading so when is loading is true disabled is true when is loading is false disabled is false so we save that now let's try that again Harry Potter and there you go now it's disabled you can't click it oh there we go so um obviously this is not how we want our data to be presented this looks absolutely atrocious and we want to fix that uh but before we do that I just want to add a little bit of a um styling change to our uh to our div wrapper we are going to change this later but this is just like so that I don't go crazy while I'm doing this tutorial so we'll say class name equals container MX Auto and container is I don't believe this is a Tailwind this could be a Tailwind um class to be honest I barely ever use it if it is but um or I never use it if it is but I do know that Shad Cen overrides it or at least defines it um as such and MX Auto is just margin X of Auto so when we save just a little bit more contained um so it's nice to have a little bit of space a little bit of breathing area white space never heard anybody um so now let's go back to our book search I am going to hide the sidebar real quick and I'm going to hide the um well no let's keep the terminal open for a second because we want to display this data as a table and thankfully shcn does have a table component which we will import like we did with the input in the button so copy that command paste it over there and once it's done I'm just going to hide my terminal again and um going to copy these import statements over and then paste them up here so now I think yeah okay so now we can um we can start actually cleaning up this data and making it look real nice and presentable uh so let's go down to this div where we had our uh our results map Li nonsense and instead of having this unordered list I'm actually gonna yeah I'll just blast it and type it over again no problem so in here we're going to open up a table I'm actually going to go back to V just so or I say V but it's the uh our running um application we're going to have a table header you know what just for the sake of time I'm just going to copy over their um boiler plate cuz why not make our lives a little quicker so paste that over there if I save well yeah I still have their data but that's fine but just so you know what it looks like um I can get rid of the table caption because we don't need that but now we can actually start rendering out our um our data so we know that we're going to have a table head um actually tell you what I'm going to get rid of these Styles too so we don't want a width of 100 PX here instead um actually for all of these we're pretty much going to do the same thing so I'm just going to do a padding of two dude padding of two there we go then I'll shift down this um four times and I can get rid of the other table heads not 2 a just two and in here we'll say the first uh column is going to be is going to be title the second one is going to be the author the third one is going to be the year and the fourth one is going to be the page count and I added page count just because that makes sense to me but you you can look at the data and see what makes sense to you if you want to show something different um so now down here in the in the uh in the table rows or sorry in the table body excuse me we want to render our table rows based on the results so for each result we're going to have a table row so we'll open up and um curly brackets we will uh iterate over the results array so we'll say results. map pass in an arrow function which we will um we Define our iterator as book and our index value as index and get rid of this curly brace and replace it with parentheses and in here I'm just going to cut and paste this table row I'm going to get rid of um this table cell in these table cells and in these table cells we're going to pass in the the properties of the book so we'll just say we'll just clone this down a few times the first one is going to be the title the second one is going to be the author name third one is going to be the year was published so first publish uh year and the last one is going to be the number of pages so that's number of pages median I don't know why they defined it this way but it's their API um now the I should note sometimes this is not available it's undefined so what we're going to do as a fallback is we'll just pass in a um a hyphen so if I hit save there you go uh doesn't our data looks so much prettier now um so I do need to actually P oops I do need to pass in this index over here so we'll say key index and this is just a satisfy react because it's going to scream at me if it doesn't have a um a way to reference the things that are changing um but we do need to also make some changes in terms of how we um yeah how we Define this uh because currently we're defining it as any because we said we don't know how the docs come back but now we know not we don't necessarily we still don't know how the docs come back but we know what shape that we want so we're going to change this to a um a type that we're going to call bolt uh not bolt book and WR um on top of us over here I'm going to move this later but for now this is fine we'll say uh export type book equals and this is going to take in those uh parameters that we showed earlier so I'm just going to copy those so control double click these a few times like so head back back to the interface uh the the book uh type does have a key that comes back which we'll use later so um the key is going to be a string hello I'm just going to clone this down a few times like so and then I'm going to paste in those values that I copied like so and um yeah so we can save that we also have another type that we are going to use it's not coming back from the rest API but you we're going to use it for our lists because we're going to have like the in progress T we're going to have the um a status of in progress um of currently reading and of done so we're going to Define that um uh type property here so this status is going to be done or so this is um an enum or a union in progress or backlog save that and we can actually get rid of the table caption because we weren't going to use that um and then I think yeah I think that's it for this one oh wait actually we need to change this any to book because uh this any for results um because now we know our results we want um at least part of our results uh they're shaped to be of type book so you'll see that our um our response comes back with a ton of results and believe it or not these are just the first 100 um um this is it's actually a lot more than this so we want to introduce pagination um so that we can uh be able to or I mean I doubt people are going to want to go through like every thousand um one of their results but that doesn't mean we don't want to give them the opportunity to right um so to do some pagination on this table we need to first um uh Define some State values for uh how many results come back as well as what current page we're on because the open Library um uses this kind of semantic for their pagination so like the page for example if you say that you're on page one and your limit is 100 that means that if there's like a thousand items and you set your limit or the limit it defaults to 100 but if you set the limit to 100 then page one is going to show you the first 100 and there will be 10 pages um but we need to incorporate this in our URL um so I guess we can do that real quick um just to kind of show you what that looks like so next to the query we will add an ENT um and we'll say page equals to um well here's where we'll actually pass in uh a page uh State value that we're going to Define in a second and then next to it we will add a limit so uh and I'm I am defining this as a um as a state value um so that you can later on if you um if you want to actually uh um have this be set by the user so so forth and so on then this is where you'll be able to use it but we will default this to 100 which is what the default normally is so here we'll say um we'll just add a few use State Snippets so use State snippet the first one is going to be the total results so this is just going to be the all the results that come back right so it doesn't give you all of them but it does give you the number of how many total results are available for your search um so we'll set total results and we'll initialize this value as zero uh the other thing we want to do is uh as you're paginating through the table we want to keep track of what page we're currently on uh because when we paginate through the table basically every time you hit hit next page it's going to be kicking off another search request with that page value so we want a way to keep track of that and that's going to be the value that we end up passing in to um to our request uh URL so here we'll say just do another use State snippet we will say um current page and then we're going to set the current page and I know this isn't um this isn't the same page as down here but bear with me for a second um so used state is going to be one uh because we're starting at the first state uh the first page excuse me which is also the default as per the um the documentation so for use pagination with limit corresponding to page know that the page starts at one so just keep that in mind that's why we're defining it as one uh wrong page there we go um so that page value is going to come from search books right now we're going to add the page as a parameter so it's going to be of type number and it's going to default to one when we run this now we always have to pass in a page if we are adding pagination and if not then the page will always be one so this will ENT or this one over here essentially acts as a default unless we override it in our request um so let's just uh add one last thing so the results. page this is just going to be a I'm just going to set this as a constant and you can if you decide later on that you want to have this be like an input value from the user then this is where you can change it so that you can make it so um now let's um underneath set results we need to set those new States so we'll say set total results so this is the total results value so all the things that come back we will set this uh as response.data do num found so this is the value that I was talking about earlier that comes back with a search result num found um this is part of the uh the API um response where was I here we go um and then we're going to set the current page to whatever the page value was so since we initialize it as one the page will be set to one but when we click next we want to pass in Page Plus one which will set it to two and then it will set the current page to that updated page now we need to actually add those buttons um so down at the bottom of the table or actually underneath the table let's add a div with a margin top of four uh Flex item Center and justify between so that there's space between them in here we'll add two buttons so we'll say button um with a variant of outline so these are shaten um uh parameters on click this is going to take in a function that will handle the um paginating to the previous um page but we'll we haven't defined that yet so we'll Define that in a second and then this is going to be disabled uh when the current page is less than or equal to one because you can't paginate to zero or to negative values or we don't wh what was that we don't want to paginate when the um is loading is true right because pagination is technically a um a HTTP request and we want to respect the uh process of the HTTP request and not send a bunch of it um while it's already loading so that's our previous um button so actually we'll right previous here and then in the middle we'll pass in just a span and we'll just say the page number which is current page okay and then lastly we'll add the next button so just copy this and paste that there um and we'll say next and um because I'm going to get errors I might as well go ahead and Define these um click handlers so there's going to be two of them we're going to have uh the previous click okay this is going to take nothing and what it's going to do is if the current page is greater than one then we want to search books of the previous page so if the current page is greater than one then we want to say current page minus one because if current page is less than one or then it would be zero then current page could be um yeah sorry uh greater than one not greater than equal to one so if this was greater than equal to one then we could search by zero which we don't want to do so this says that basically current page has to be two or more um than we want to be able to um search the books of the previous page uh so let's go ahead and duplicate this and we'll say handle next click I am going to zoom in a little bit so it's easier to see um so for handle next click we are going to do a little bit more logic over here so we're going to say if current page is less than the math. sealing this is a JavaScript method total results so these are the total results of um like how many hits were found from the API divided by by the results per page so if the current page is less than the total results divided by the results per page um we will search for current Page Plus One okay now let's copy these two like so and then head down to our click handlers and we'll just paste them in there save that and you'll see that we are currently on page one even though like cuz our default page is Page One um even though we don't have any results but let's go ahead and fix that so Harry po okay so we hit enter and you'll see that um we have our next and previous button which um are currently disabled actually because I didn't fix this uh disabled let me actually do that so I'm actually going to use the same logic as the Handler over here so copy that head back down to the disabled paste that there and that should have worked and that is not working because I am using the wrong logic uh it's not supposed to be current page less than it's supposed to be current page greater than or equal to uh the math cealing total results um divided by results. Page or is loading is true save that so there we go so I want to click next searches finds the next page do that again searches finds the next page so forth and so on uh I do need a way to indicate um what like what search page we're on because well we don't know how many results came back um so we need a way to basically keep track of the um search index so what we're going to do is underneath our click handlers let's just Define two values so we'll say const starts index and we'll set this equal to current page minus one times the results per page plus one okay so this is basically like um like if we want to say we're showing one out of 100 of this many this is how we do that so we say like the current page minus one times the results p uh per page time uh plus one and we're going to have the constant index so uh whoa what did I say const end index I am tripping um and this one is we're going to basically do math.min and in here we're going to take that start index that we just calculated and we're going to add the results per page so if we have 100 as our results per page then it's going to say uh the start index if our start index is one this is going to be 101 but since we're actually only returning 100 we're going to have to do a minus one or total results and the reason we're doing the total results here is because if your uh search comes back with like 70 things then it doesn't really make any sense to do showing one out of 100 when really you only had 70 results show up right so this way we get the minimum it's either going to be the total values per page assuming that your results are bigger than a single page or however many results came back it'll find the minimum of that so that that's our end index and now we need to actually show this somewhere so let's uh let's under our button We'll add a div the margin top of two and we'll say if the total results are greater than zero then open a paragraph tag with text small and in here we'll just say showing start index to end index out of total results to uh results save that and you'll see showing 101 out of 200 out of 3581 total results so now that we have our um content displayed we need to actually be able to do something with it right because this isn't going to help if someone wants to create a reading list so we need to add the functionality to add an item to the reading list um so let's head back to our app. TSX I'm just going to close these out like so cool so in app. TSX um we're going to Define find a state variable um so we'll say const books set books so these are the books that the user um has added to their list and then set books will allow us to set the books and we'll say use State import that and this is going to be an empty array uh to start and uh since we do have book defined we can actually say we can import that from the book search uh file and I'll just yep there we go but it's actually not one book it's an array of books cool um and what we're going to do is we're going to have a hello we're going to have a function called um adbook oh and we also need to have a place for these books to be persisted right so we want to store them in the local storage so we'll add a use effect um which I need to import like so and what we're going to do is um we're going to first need to figure out what books we have stored in our local storage so we'll say const stored stored books equals local storage dog item and um we're going to Define our local storage uh variable for this uh particular data as reading list and we'll say if store books because remember stored books might not exist so if it doesn't exist this shouldn't run but if it does exist then we can set books to json.parse stored books um that's not right parse there we go okay uh we don't need a cleanup function for this one so we'll get rid of that and we don't need a dependency array so we'll get rid of that now you might be saying well what happens if there is no local storage item to that I say we will create one in our adbook uh function so we're going to say const adbook and this is going to take in a new book with a type of book and in our function block we'll say const updated books so this is like our new list of books this is again assuming that we already have books but book and this is going to be um whoa what did I just do so this is going to be of type book equals to an array that is made up of all of the books that currently exist as well as the new book let's try that again the new book so the data that's passed in um when we add a new book with a status of backlog and what this basically means is when we add a new book it will um it will pass in it will expand the properties of that new book and also add the status of backlog so that by default when you add a new book automatically goes to the backlog um that way it's like uh you you can add this functionality later where it's like if you say if you want the user to have like to add a book directly to their like currently reading list or so forth and so on but in my case I think it makes sense just to have it default to the backlog and then the user can manage it from there um so let's see um now we need to actually set our books so set books to the updated books value that we just defined which is currently screaming at us because we didn't there we go we didn't put the arrow in the arrow function um and now that we have our state value set excuse me now that we have our state value set we actually need to persist this in our local storage so we'll say local storage did I spell that right yep do set item so what set item will do is yep there you go so if uh if nothing already exists it will create a new key value pair so if this is the first time and there's no local storage set then when you add an item it'll create that value and then add um the content to that uh local storage value so we'll pass in the key of reading list and then we'll say json. stringify because local storage requires everything to be in the format of string updated books cool so now we can take this function and we can pass it in as a uh as a as a as a callback function to the child's component of book search so we'll say on ADD book equals add book and what this functionality allows us to do is um we're basically passing a state Setter function so this state is at the app level but because we're passing this function down and because this sets a state at the global app level whenever we add a book in the child component this will essentially allow us to modify the state of the parent which in this case is app so if you're ever wondering well how do I like how do I have a child update the state of its parent this is how you do it we are going to intr zo stand for Global State Management later which will make all of this like unnecessary but for now this is um this is pretty much uh yeah this is good enough um so you'll see that we're getting it um an error from our IDE because onad book does not in fact exist and that's okay we need to go into uh book search and Define it so inside of book search let's open up a curly brace and we'll say onad book and then we'll Define the types um as onad book this is a uh Arrow function that will take in a parameter of book with a type of book and will return nothing which is void so what this is basically saying is um it's going to take an onad book as a function which it it is and um that function is going to be of type this function yeah you can have a fun you can have um functions as as a type it's a little wonky but it'll make sense um after you do it like a couple hundred million times um so now that we have that function being passed in we need to actually use it somewhere so if we head down to our um to our table cells we can add in a last table cell um which will actually take in a button so I'm going to zoom out for this a little bit because it's going to be hard to see there we go so this is going to take in a button this button is going to be a variant uh link because it's just going to be a word um and in here we'll have a uh click Handler and that click Handler is going to take an anonymous function which will run on ADD book now if you recall onad book requires a book so I can pass in book but you saw how much data comes back with each one of these books which is like a lot to store in someone's local storage and it's unnecessary we don't need all that all we need is the things that we defined in our type up here so I'm actually just going to control click all these um and I'll control click status even though we don't need to it's just for completion sake paste those there and then for all of these I need to actually out of colon and then because I'm super lazy just going to control D all these the next time I'm going to do book. paste book. status does not exist but it's fine because we want to default it to backlog and um we need to add a bunch of commas over here like that and uh oh another thing is number Pages median remember how I said this could be undefined or null so what I'll do here is I'll just say or no and that's going to scream at us because I was supposed to Define this as a optional like that so now wait was that not right oh no I'm a silly goose it's not an optional actually uh there are few errors that I have here this is supposed to be string or null so uh undefined is that it's undefined null is that it doesn't even exist so it's not even there um which is usually the case it doesn't usually come back where it's number of pages median why did I do a double or there there we go um it's usually that it's not even there which will be null in that case um we also need to have the author name being an array because I found out that like they store multiple like when you have books that have multiple authors they will store them as an array instead of a string so just need to make sure sure that's consistent um and oh gosh my least favorite part is closing this oh this is the button so I'll just close that button and in here I'll just type add and um yeah I think if I save that come in here Harry Potter you'll see we have the add button um but we are I don't know if I should add an empty table header but I'm going to because of completion sake so just so that um we don't have a mismatch in terms of our header and our body and then I think yeah uh now we can go on to actually list off the things that the user has added so let's go ahead and um we can add as many things as we want but well with where did they go well that's a great question because I have the answer for you right now we need to create a new component that we will call book list and this is going to um this is where we're going to do all that fun stuff that I showed yall earlier um where you can like move things around and see all the different statuses and all that kind of all that kind of jazz so in here uh we're just going to say I don't know why I started typing book type book so many times like glued to my fingers at this point so um we're going to have our book list component um how are we going to render this you know what let's just show the books as they are um ah no we don't need to do all that we already we already know what Jason looks like so we are going to need a new component from shaten uh this is going to be the card component which is all the way up here um now the card going to grab that control Tilda paste that there isn't it nice to just have components like like that instead of having to import a million things and then deal with like you know figuring out what dependencies you don't need and what you do need um okay so now um back in book list we're going to we're going to actually set the book list so that it takes in the um books we're going to pass these down from the app uh in a second so we'll just say this is actually supposed to be an S so books and then books are going to be of type book bet you bet you wouldn't have guessed that um now inside of here we're going to have uh so we are going to have a ton of books and um we're going to have them show up differently um so I'm going to like get ahead of this and Define a template inside of our jsx and we're going to do this pretty frequently so I might as well get this out of the way now so we're going to say const render book item and uh in here this is going to take in the book and an index value index value there we go numer number I can't type I can't even read got I'm making thing about books okay so I'm getting errors and I don't know why but it's okay um so in here all we're going to do oh I'm getting errors because this is not a function block this is just a returning jsx thing uh so in here we're going to grab that card which I need to import so I'm going to copy these over and I'm going to paste them there so and you know what I'll just copy this cuz I'm a lazy boy and pays to be lazy um but we don't need everything here so first thing we want is because this is going to be an array we need to pass down this key so the index um at the card we are going to have the card header the card header is going to take in uh the book. tile and then the card description is is going to take in the book. tile psych it's going to take in book. author name um and we are not going to have a foot or a body so I'll just yeah Foo or body content yeah we can get rid of those um I'll keep these here for now because um spoiler we are going to need them in a second but just not right now um so inside of our return statement we're going to say a we're going to say this is a div um I don't know space uh vertical spacing between things so we'll say space Y8 do padding 4 and in here we're going to have a header um with a margin bottom of four a text of 2XL that's an L not a one and then we'll give it a bolt font we'll say this is my reading list Herer just kidding uh um down here we'll add a div and inside of that div we will go through our books array where we will pass in the not the boss the book I don't know why boss came to my head index and instead of this curly brace we're going to return render book item where we pass in the book and the index now I am well aware that I could have just done this and pasted that there but like I said this is going to get a lot more complicated so we're just going to get ahead of it now going to save that and I'm going to head back to app and I'm going to need to import the book list component here book list component and this is going to take in as we said earlier the books like so so now we can save that then we head back to our app and there you go there's our reading list we have the philosopher stone Deathly Hollows prisoner of askaban let's add the Half Blood prins added isn't that phenomenal look at that and now because we have it in our local storage if I refresh they stay there okay so um now we need to have a way to manage our book list so you know move around based on status because right now all the books are just kind of there right and that's that's not desired Behavior that's not good ux for what we need so inside of app. TSX we're going to add a new function called move book so we're going to say const move book and this is going to be an arrow function it's going to take in the book to move uh which is going to be of type book new status which is going to be of type book book status de there we go um so inside of our function block we're going to do the same thing that we did over here where we const updated books but we're going to do something spicy we're going to say this is equal to rather than doing it this way we'll say it's equal to books. map because we need to update a book right when we're moving a book all we're doing is we're changing the Status so what that means is we need to find the book which is book to move then we need to update the status based on the stat the new status so we're going to say book. map so this is going to iterate over the books array and I don't know why I pressed enter there we go book and inside of this uh Arrow function we're going to basically say if the book key so if the current iterator is equal to book two move. key then we're going to say book but the status so the the book meaning the the the book that we're iterating over but with a status of new status so this is going to update the status of the book otherwise just return the book so it's going to go through the array it's going to say if the book key is equal to the desired book so the book to.key then update the new status of that book otherwise return the book and then move on to the next book in the array um I need to do something but I forgot what it was oh yeah well I defined updated books but now I need to actually use them or set them so we're just going to copy that from there set that and then we're going to um excuse me and then we're we're going to also update our local storage like so so local storage set item yep that looks good so now we need to pass in move book to our move uh our book list component so we'll say on move book equals to move book save that and now head back to our book list and inside of our book list we are going to um add a parameter called on move book and this parameter is going to be of type or prop I guess technically on move book with a type of a arrow function that errow function is going to take in a book of type book and a Target list I'm so sorry I feel like I feel like if someone watched this tutorial they're just going to have the word book just ingrained in their head which is not the worst thing all right so um it's going to take in the book and then the target list so this is where like it is technically the book status but remember the book status is also the name of the lists right so we're going to be calling it Target list here um but it's the same thing because this is the second parameter it doesn't matter what we call it that's just the the this this property name is relative to where we are um if that confused you more don't worry about it void and and let's see let's save that just to let prettier do its thing cool so now we need to use on move book so remember this is a callback function so whatever we do here will affect the state of the parent being books so um let's say const move to list so this is what we're actually going to do when we on move book um this is going to take in the book and the target list book status and this is going to return the on move book book Target list and I'm just even I know I could have done this in the place that I'm using it but I just I I prefer to make things a little bit clear and consistent and plus as you guessed this is probably going to change in a little bit um so it's going to be easier to refactor later so inside of our card remember how I told you we're not going to get rid of the card footer and that's because we need it here so we're going to say card footer and inside of that footer we're going to have a div with inline flex boox and a gap of two between things and inside of here we're going to have all the buttons that we use to move things so we're going to say button am I importing button I'm not just going to grab that import statement from here paste that there and as we were doing we have our button this is going to be a button with a variant of outline um and when we click it it's going to hello oh gosh let's try that again it's going to be an anonymous function that is not taken in a plus we are having technical difficulties and we're going to move it to the list in progress so you probably guessed it already but this book this button excuse me is going to be used to move things to the in progress list so here we'll just add the label of in progress and we'll save and you'll see there's a button that says in progress cool so um um if I actually click it you're not going to see anything happen and that is because we're not actually rendering different sections for each one of the statuses so let me quickly uh duplicate these books down uh we'll say I think the other status was um done do we want to do done first no backlog backlog first so backlog and then done done so when you click on this one it'll mark it as done if you click on this one take it a backlog and so forth and so on click on this one take it in progress and you get the drill but now we need to actually show it because you don't see the state the state is changing but you just don't know it and I'll prove it so if you go underneath my reading list we need to um we need to basically render different sections for each one of these so we'll say that since books is a single array we need to filter through that array for each one so we'll say books. filter pass it an anonymous function book and this is going to return if book. status is equal to in progress dude I cannot spell in progress so this is saying is if the book. status is in progress if that book filter. length is greater than zero then return this but it's actually not going to be books. map it's going to be books do it's going to be this again actually so just copy this um tell you what we're going to do we're going to have to do it like so so we're going to have to open this as a parentheses um then we're going to have to open up a react fragment because we're going to have multiple children in here just paste this in there and um we're going to have to have a header uh with a margin bottom of two large text and sendi bold font in progress cool and then underneath it uh rather than doing books. map we're going to once again do books. filter so we're basically going to grab this and we're going to paste it right there oh nope right after books so this is going to filter the books by in progress then it's going to map over that filtered um that filtered array and then it's going to render the book item um so if we save that you'll see that now we have our in progress books and don't freak out all we have to do now duplicate this down twice and we'll change the second one to backlog backlog and we'll change the third one to done and done and there you go so now you see we have different lists for well our different lists um I think I'm missing something right I have have an error don't know what the error is am I passing in the index I am passing in the index um let me see oh I know what I need to do so I am going to get rid of card content sorry I I was looking at my notes um and I actually uh there is an issue where like if you're already in the backlog then you shouldn't be able to press this right you are pressing it but like you don't want to be able to you want to disable that button so what we're going to do here is we're going to say that uh for each button we're going to set it a to um whether or not the uh current list that this book is in is in progress so we'll say list type equals equals equals in progress so this will disable any of these buttons if they're in progress but you might be wondering well where the heck are you getting list type from and that is something that we're going to need to pass in so if we come up here we add list type as a parameter and we'll set it to string and then down here in each of our render book items we're going to pass in the list type so for the first one it's in progress for the second one it's backlog for the third one it's done and now back in our buttons we can add these disabled states to each one of our respective buttons so this one is not in progress It's backlog and then I'm going to hide that there we go and then um in this last one it's done so now when we save you'll see that it disables the button that uh corresponds with the current status so if I move this to back hello well that was not supposed to happen Okay so I had to take a second and um verify um something but basically I uh set my filters wrong because I duplicate well I duplicated them and I forgot to update them in all places so this is supposed to be um backlog and this is supposed to be done so if I save those now we can actually see our different um categories so we have our done State move that to backlog move that to done cool um move that to done so you know you can kind of see how all this looks so next thing we want to do is we um well we want to add the uh remove uh from list functionality because let's say you have like something excess stuff in here for example I have Deathly Hallows twice I want to get rid of those um so we're going to add the uh remove book function to the app the same way we did it before so we'll say um const remove book equals nfn book to remove is going to be of type book and then inside of our function block we want to First have an if statement where we can confirm that the person wants to actually remove the book so we'll say window. confirm this is just a um a uh window API feature so this comes with all browsers basically um and we'll say are you sure you want to remove this book cool if this comes true so if the user does confirm then this will be true then we will do the same thing we did before um where we'll say con updated books equals books. filter so we're just removing the books from the the book from the books array um we'll say book and if book. key does not equal to book to remove. key so what this is saying is it's filtering the books by everything that's not the one that you're trying to remove um yeah it's it's shorter to do this than the alternative so instead of having to find the key all we're doing is we're going through every single book in the list and whichever one um uh if there is one that equals this it will not be returned in the filter only the ones that don't equal the book that you're trying to remove will be returned um to uh by the filter so yeah so now once we have updated the books we are going to set books actually let me get rid of this curly brace cuz this is a Anonymous inline function and we'll set books to updated books and I'm just going to copy pasta um this line right here because it's basically the same thing so now that we have um the remove book we need to pass it to the book list the same way we did before so on remove book equals remove book save that really thought that would get formatted but I guess not um head back to book list and inside of the book list we will pass in on remove book and it's going to basically take in um yeah uh I I duplicate this down um I'll say on remove book not poop we don't want to remove the Boop so we'll just get rid of the status because we don't need that and we can save that um and now we need to actually use it so inside of the footer um I added this Flex so that these buttons are kind of grouped together um or added this div I should say and then on the other side we're going to have um I'm actually just going to copy this paste that there this is going to be uh variant destructive which is just going to make it red and for the onclick it's going to be on remove book and it's just going to taken the book because it doesn't need the status and um we're not going to disable it because we have the confirmation um so we'll just say remove save that and I want to kind of separate them I don't want the remove to be on the same side so to do that in card footer add class name of flex and then justify between there we go so now we have our remove on one side all of our things on the other if I want to remove phos for stone do you want to remove this this is the confirmation that I mentioned earlier at work hit okay you see it got removed now if I remove these two well I say if I remove this spoiler alert it'll remove both of them and that is because we removing Things based on the key these have identical keys so as far as our app is concerned they're the same thing and you could be saying well that's not desired Behavior we only want to remove one to which I will say no we actually should not have had those there to begin with and that is going to be something we address in a little bit um when we get back to our table we're going to add a um we're going to add a um a disabled uh value to the add button which will basically um it'll it'll compare the uh each one of the items in the uh table array with what you already have in your reading list and if it's already in there then it'll disable it so that you C you can't add it to your list unless it's uh if it's already in there so I do want to add a state management package because uh while we can keep going by moving um these functions from app uh as callback functions and allow the state to be modified by child components it's not as clean as if we had a state manager where the state is decentralized um and don't worry we're not introducing Redux because I do not like Redux well there's nothing wrong with Redux except it's sometimes um a little bit too much so what we're going to use instead is uh Zoo stand so just yarn add Zoo stand hit enter and now um what we need to do is create a store so inside of my source folder just going to do store. TS you actually don't need to define a store I just prefer to um it's it's it's what like you can technically have a store in every single one of your files um because uh the zoo stand state is basically like um scoped at individual stores uh individual Zoo stand stores but in our case we are going to treat this as a global store so that's kind of why I'm doing it this way um so we're going to import create from zo um and what we're going to do now is uh well we're actually going to move things around a little bit so let's go to our book search and let's yoink the book type from here um and paste it inside of our Zoo uh store uh and the reason I'm doing this because I want the types and everything to be kind of centralized where the store is um is being defined and used so well not used it's going to be used all over the app but yeah so um so we have our book type in here now we're also going to need uh to create an interface for our book state and we're also going to create an interface that extends the book State called bookstore and this is going to have all of our methods um so add book remove book move book and load book from local storage which you haven't seen yet but you will see because we're about to use it um so now let's head down and create a new store so what we're going to do here is we're going to create a use store meod method which is going to um run create us uh create create excuse me from Zoo stand with type bookstore so um it's going to take in this interface over here which includes the book and in here we're going to initialize the state values as well as the um the methods so books will be initialized as an empty array and our functions are going to be initialized like so um so let me just space these out a little bit so it's easier to read and we're going to move all of the uh current functionality that we have into these function bodies and all this is doing is um when we're running these functions it's setting this it's U uh we're setting the state to whatever the output of the function is um so let's go to app. TSX and actually grab these functions out of here um let me see so I believe I can just grab the inside of the three of these so we're going to just contr uh X that and in adbook going to paste this in here and at the end of the uh at the end of the adbook method um we're going to need to return the books as updated books and get rid of set books because we're we're not actually um we're not actually uh excuse me we're not actually uh setting any books and because we're not using the use State anymore now we have to say state. books so um yeah so now for remove book let's do the same thing um we come down to remove book contrl X that head back to the store paste that in there and say state books and then we can get rid of set books and all we do for this one is uh well actually outside of here we return state but inside of the if statement we will return books equal to updated books and what this means is if window confirm if Windows if the window is confirmed if the window confirmed dialogue thing is set to true then it'll return the updated books it'll set the uh the books um property as the updated books which will exit this function but if this doesn't run then the state as it is will be returned meaning nothing happened so let's do the same thing for move we will grab this cut go back to the store paste same thing in here we can get rid of set books and we'll say state do books and where is the last part um yeah we just need to return oops return books as the updated books like so so and uh let's see what else are we missing oh I do need to export the use store I don't know why I just thought of that but export you store uh I think oh yeah the local storage so what this one is is um this is just letting us grab the um the uh stored books from the local storage so this is doing what we were doing um what we were doing over here so we're saying ah you know I'll just go ahead and grab this so we'll uh cut that out of there and then we will paste that in there and we're not actually setting the books instead what we're doing is we're running the sets method which we uh are getting from the create method so we're going to set um the books to the Json parsed store books and um otherwise this is like in the case that there are no books then we'll just set the books as an empty array cool we can save that and now let's go ahead and start Distributing these across our app so first thing we'll do is in app. TSX we're actually not going to use these this way we're going to remove all of these and the use effect actually well actually we'll keep the use effect cuz we do need that and we need to import um the functions from the Ed store hook so in order to do that we'll say use store just to import it so don't import it from use uh from zo stand import it from store um so now we're going to have to destructure const uh the load books from local storage out of how hello that's supposed to be oh my gosh equals use store um state state cool so we're going to grab this method from our store and in our use effect we're going to run it when load books from local storage first uh gets imported so when we get this method we'll run it meaning this will run on first load um so now let's actually get rid of the functions that we pass in to these components because now we don't need to do this because of the fact that all of our oh and we can get rid of this um this state Setter because we're not using it anymore so because we're no um we're no longer using the app to pass down this information we can um and because we're using the store we can head to our individual components and do the same thing where we import um the functions that we're going to use directly from The Zo store and because all the data is going to be stored in the zo store it's all um it's all going to be like uh coales in one place so we can get rid of this past in prop uh uh excuse me Properties or props and we'll do the same thing that we did before so we'll say const we're going to grab books and add book from use store and this is oh no nice interesting use the app for this one I like that okay um state state and let's uh quickly use the wait hello bookus assigned but never used oh wait I also need to import I need to import book now because we moved that to the store so we imported the book um oh and I remember why we're importing books so we're importing books because I mentioned earlier that we um we want to update our button so that if the item already exists if if an item already exists in our list we don't want to add it and we're going to use the books like our current book state to check that but for now let's resolve this error so let's see add book so it's no longer on adbook um instead it's just adbook and let me double check something before I save this so yeah um so we are going to have to of this probably um yeah well let me actually fix this real quick so in our um where am I going in in our store we have it so that it's setting the new uh the data that we're passing in from the new book which if we do it the way I was about to do it it's going to um it's going to completely overr oh my God we can't even read that there we go so well no that's right that's right so this is going to pass in this information yeah this will work I'm pretty sure if this doesn't work then I'll eat my words um and I guess while we're here let's go ahead and uh fix that um disable issue so oh and we do need to pass this no this is right this is right okay so um underneath the uh The Click Handler we're going to add a disabled equals books do sum so some book uh where book of book. key equals equals equals oh wait actually we can't use book because we're already using book so we'll say B I guess Shand so um wherever the current books uh equals to book. key it will disable um the add button for that so now let's quickly go and resolve the issue in the um the book list because we're no longer using these functions in this way so I can actually blast this away and I am going to copy um this where did it go um come on now dude oh there it is I'm gonna Co not the whole file just that I'm gonna copy this over to um the book list and um from here what we're going to do is we're going to get rid of AD book we're going to say remove book and move book and now I can just replace on moove book with that and I can replace remove book or excuse me on remove book with remove book and I think if I save that oh I do need to import you store from the store and I'm pretty sure I need to import the book yeah that's not imported from the right place so just get rid of that paste that there save and there we go um so now our zo stand story I believe is working in progress done backlog remove sure you want to remove yes done okay cool um oh and let me double check something real quick Percy Jackson so I'm going to add the Lightning Thief and because I added it now it's disabled um so I can't add it again so we fixed that issue so real quick before we move on to like styling this I do want to um clean up some stuff real quick so uh this list type over here this is technically of the book excuse me sorry the book status type not string so we paste that in there like that because we want um the list type to always be one of these three right um so there's that piece and then if we head back to our book search we want to um we want to add a conditional uh rendering for the table because it doesn't really make any sense if I refresh it doesn't make any sense to have like the table show up when there's nothing in there um so let's head down to this uh this table component and I'm going to wrap this in a turn operator so we're going to say uh query query. length is greater than zero so assuming that you've actually dude what in the world greater than zero um so assuming that you actually typed something in there um and where is my Ampersand there it is uh results. length is greater than zero and I know there's better ways to do this but this is just like for demonstration purposes I encourage you to do this the correct way this is just like me um doing this for y'all to get an idea of what I'm talking about so we paste the table in there and then otherwise um otherwise we're just going to have pass in a div uh with a flex box no not divide what div. Flex okay it does not like that we have to open a parenthesis I think div. Flex there we go um max h60 um item Center justify Center um padding of 16 and in here we'll just pass in a a paragraph that says start your search there you go so now it won't show the table unless there's a table there or unless there's stuff for the table to actually um render so if I say U if I say uh what's that one with catus everine Hunger Games Hunger Games um there we go now we actually have stuff and I'm going to go ahead and add the Hunger Games um and now we want to get into the last part of the modification of the state or of the list which is reordering them so we first have to add a new state function to um to our Zoo store and we're going to call that reorder books it's going to take in a list type the start index which is the um index of the array item when you begin or or begin it before good Lord before it gets reordered sorry I'm stuttering before it gets reordered and then the end index which is where it is like what its index will be after it's done reordering um so let's go ahead and add uh underneath move book We'll add the um reordered books function down there and uh the first thing we're going to want to do is we're going to want to create a new array that filters um through the current states books um so that it only includes the books that match the filter type so yeah so we're State books. filter and then um we're just going to check the status uh and and return the books that um are the same as the list type that's passed in um next thing we're going to want to do is we're going to want to remove the book that um corresponds with the start index from the filtered books array so we remove that reordered book from the filtered books array um and then we're going to want to insert that reordered book back into the filtered books at the end index so wherever it is that we're finishing off this reordering process that's where we're going to insert that new reordered book lastly we're going to as we did before where we created the um the update books uh arrays we're going to create update books and to do this we're just going to map through the existing books array and then wherever the book status is equal to the list type that we're passing in then we will replace it with the next book from the filtered books otherwise we will um just return the book as is and lastly we'll just go ahead and copy paste that local storage Setter and return those updated books so go ahead and save that and we seem to have an issue let me just see what's going on local books from local storage oh that is because we didn't add a comma there I think yep there we go okay so now let's go ahead and use this thing in our book list component and um before we get started with this let's actually we need to install two packages so we need to install um react beautiful um beautiful DND which is uh the drag and drop package that we're going to be using for um uh uh for reordering our lists and uh we also need to add the types so r. d-d excuse me types react beautiful DND okay and um once you have those installed there is uh something that we have to do uh before we can use them um as of react 18 um the droppable function in react beautiful DND uh doesn't work with uh strict mode so in order to get it to work um there's like this workaround that I was able to find um until atlassian decides to to solve that particular issue um this is going to be the way that we do it so that we don't compromise um react strict mode so we're just going to create a new file or a new component call it strict mode droppable . TSX and I'm just going to paste this in here um I'm going to probably paste this uh this link to this medium medium article excuse me explaining um how this works because this is not my code I I lifted this from um from another uh GitHub answer and it it listed this as a reference so um this is how we get it to work um with react strict mode so you know yeah go ahead and do this first pause get it copied and once you're done with that we can head back back to the book list uh component and there are a few steps I did struggle to to figure out like how to best um I guess uh explain this next part and because to be honest it is a little bit more of an advanced use case but uh what I figured we'd do is start off with like kind of um the I guess the end goal right or the end result so we we want to be able to drag these items and have it um and have it reorder the books at the end of the drag operation right so to do that just add this function uh called on drag end uh I I did pre-write this because um this is really a onetime use case uh for this project so we're not going to go into too much detail on it but in essence what this is doing is uh whenever an item is dropped um like or at the end of the the drop event um what's going to happen is the the first thing is um the result that is passed here is going to check whether or not the the operate the thing that was dropped whether or not it dropped it dropped in it was dropped in a destination that is uh valid um if it doesn't so if result. destination is false meaning like if I drag and drop the thing outside of its like designated drop area then it will just exit the function um assuming that's not the case then it'll first get the source index or the starting index um of the uh the item that was dropped then it'll get the destination index so this is part of like react dnd's uh internal working so it has the uh information on where it was dropped relative to um that the items in the array and um after that it'll grab the list type from the thing that was Dr dropped so we're going to pass in the uh droppable ID um uh excuse me we're going to drop in the um the the the dropable ID is is the actual uh ID that's passed to the context of the drag drop area and because all of our drag Dro drag drop areas are going to be uh segmented by the list type that means that the droppable ID is the list type and that'll make a little bit more sense once we get down to the context part of this lastly we're going to reorder the books based on the list type the source index and the destination index so this is the reordered books uh function that we had um defined in our store which we'll go ahead and import as such so now we actually need to use this um on on drag end and what we're going to do uh because we're only having uh we're only making the backlog and the in progress arrays uh drag and droppable what we'll do is um we have to create these uh they're called uh drag drop contexts this is also from the react DND package so right underneath the um heading for uh the my reading list heading we'll just add um these uh dragdrop context wrappers so we'll wrap drag drop context there we go so went ahead and imported it I think it imported it did it not oh no it did it did I just yeah there we go uh I just had my jsx wrong um so uh in this drag drop context that's where we pass in that on on drag end and this drag drop drag Lord I cannot speak this drag drop context this is going to um this is going to use the list type uh that is provided um in the we're going to add it in a second but you'll see where that list type comes in from so let's go ahead and add another dragdrop cont context around we added this to the in progress and now we need to add it to the backlog so there we go and I'm not going to add um I'm not going to add drag drop ability to the done because it doesn't really make any because the whole the whole idea behind the dragon dropping the drag dropping is to reorder the list based on priority but if you've already finished if you've already done or you're done with your reading list then it doesn't really make any sense to be able to reorganize based on priority cuz all those things are done um so we're just going to leave this one um as is so now we actually have to um create a dragable book list so these are um it's essentially going to replace what's over here um and this is where we're going to pass in that um that list type parameter and make it the D the droppable ID so I am just going to paste this function in here go ahead and pause and copy this over um I'll wait wait and when you're done uh well just make sure to import these so this is from the strict mode droppable that we created earlier and we are missing a few Imports we need to import our dragable like so and uh we also need to import our drop result um like so cool now uh what this um what this book list this render draggable book list is doing um first and foremost we're passing in the list type uh to this render draggable book list function um so this is going to replace these down here in a second and the first thing that it's doing is it's filtering the books by the list type right so for example if we have the in progress books we want to filter those out if we have the um the backlog books we want to filter those out uh the next thing that it's going to do this is going to be hard for me to explain but I'm going to try to do my best so um it's going to first Define a drop zone for uh the items that match that particular ID and this is where that droppable ID gets matched with the list type so that means that the um in progress compon uh the in progress status items are going to have their own droppable context and this is where um this is like that going to be that valid area where they can get dropped and that um that function actually returns a object called which we're going to Define as provided uh that contains props in a ref that need to be applied to the component as a whole and they'll gosh my Intellis is going crazy and they'll be applied at this first uh div so this div is going to represent the entire droppable area this thing right here so this represents the area where we can drag and drop things um inside of there we want to render out those individual items so we'll say filtered books. map and then inside of here we'll Define every individual draggable item so each one of the filtered books meaning the books that match the list type um that was passed in here will have their own um their own draggable component which will take in the book key uh as well as uh and that'll be that'll constitute the dragable um ID as well um and this is going to return a provided object for the dragable um object what we're going to do here is we're going to then create a div that is going to um contain all of the functionality uh that's provided by the drag bable object and we're talking about like things like um The Ref for um for implementing the uh DND dragable functionality and any of the additional props that it needs um to actually work and then then inside of that we have one more um div which is going to constitute the drag handle so the thing that you actually grab to drag and in our case we're going to make the um the drag handle be the entire thing so anywhere that you click on the thing you can click and drag it and that will be a valid uh drag handle so I hope that made sense um if not I would recommend looking a little bit more at um react D and's docs I'm not too great at it so sorry if I like butchered that explanation but tried my best um so now let's go ahead and put this in action uh so under the um in progress we can actually replace this with our render draggable book list function and pass in the list type of in progress and we can actually do the same thing with the backlog so we'll just paste that there and then we'll change this to back if I can spell backlog okay and we don't have to do anything for the last one because the last one will not be changed so we can save and now at long last I can click this item I can drag it and it'll update its position if I refresh actually let me check that again yep if I refresh it'll persist that order and there we go we now have completed our uh well basically everything pertaining to I guess CR operations within um the context of this uh this app so what we're going to do next is add the components um that we need to just clean up the uh the layout and Implement dark mode so first thing we want to do is um well I'm actually going to paste some code from my other uh tutorials and I will link the tutorials um that I'm referencing in the description I'm going to see if I can like put up cards um but if I can't then I'll just uh I'll add like the link to the timestamp so if you haven't followed my previous tutorials and don't have that code I would recommend going and checking out just that part of the tutorial otherwise you can pause and just copy whatever it is that I paste in here so first one I'm going to add is a uh I'm going to add a hooks folder to my source folder real quick and I'm going to first add the use theme. TSH hook and this hook uh for the quick and dirty explanation all it does is it allows us to um to use the uh the user's preference or whether or not the user has visited and has changed um the dark mode setting in the past this will allow us to access um the user setting so the um the they're they're like prefer dark mode setting if they have it on their browser um or if they visited the site before then it'll whoops then it'll actually store that value in the local storage so that the next time they come um their settings are saved so go ahead and copy this over um if you want to or you can go to the other tutorial and follow this part so just going to pause here for a second and then I'm going to scroll and pause here for a second I'm trying not to like um I'm trying to be better about my zoom uh level because uh someone had pointed out previously that I tend to zoom too far in my tutorials um so once you get that done you want to head over uh to your components folder again and we're going to create a new comper a new comper good Lord a new component called navbar navbar TSX and inside of the nav bar we're going to add two components we're first going to add the theme toggle the theme toggle is going to use the used theme hook so we'll import it like so and it's also going to use these two icons which I'll Import in a second um the other thing that we want to paste is the actual nav bar which will use the um theme toggle button so I'm going to copy and paste that with the um description of it oh gosh there we go um yeah so I'm going to pause at the top let you copy all that down and now I'mma pause over here so that you can copy all that down and like I said all this code is the same uh as what we've done in the previous tutorial um I just need to update the icons real quick so let me just import those um so those are coming from the react icons package which I conveniently don't have installed so let me go ahead and install that yarn add react icons this is a phenomenal package like I think it consolidates all the uh popular icon uh packages um just hide my terminal there we go so we can save that and uh the last thing we want to do is we uh actually want to use this um this nav bar in our layout component name so you'll recognize this from the uh build your own UI components Library um tutorial um so I'm going to add a new file call it layout. TSX and this is going to be a wrapper for our entire application this is going to require us to import the Navar like so save that and go ahead and pause and copy this over if you don't already have this code and now we can actually go back to our app and wrap our entire application with that so let me first find where that is um yep there it is so instead of this container I'm going to replace this with layout and we'll import that from do components layout save that and um o yeah baby because I already have dark mode enabled automatically defaulted to dark mode like I said and um there we go we have our light mode and our dark mode few little links that I like to um add in there so head back to the book search. TSX component because now it's time for us to um update the Aesthetics of our table because after adding that dark mode well really does look atrocious so um at this top div replace this padding with this negative margin and this x overflow um let me just scroll back up over here cool next thing we want to do is this entire thing so all the contents of this div we're going to wrap it in another div so we'll just crl X div paste all that back in there and then for this div up at the top we're going to add the following Styles and these are just going to add a divider um when it's a certain width and um make sure that divider has some nice little dark mode aesthetic so there you go some nice little lines and clean a little divider um after that we want to um we actually want to add a wrapper around the input in the button because when we resize um oh I totally thought that would work there we go when we resize this we want to have our like small screen version of this we want it to look a little bit uh neater we want that like that input box up top and the button to like be the same width and so forth and so on so let's go ahead and um add some a little something something to that clean that up so uh that button and um well I think I guess actually the we can actually get rid of this because we don't need this anymore the results information we're going to replace this in a second so get rid well tell you what we'll just comment that out for now because we are going to replace it with something else um so we're going to take the button and the input I'm going to wrap these in a div and that div that we're wrapping them in will contain a flex box like so and inside of that first div the one that has the input we're going to add a relative width full to the small um oh I should have replaced the whole thing to the um the small Max width and this will make sure that like when it's um when it's at the small break point or larger it will have a maximum width but up until that point meaning like when it's still on mobile it will have full width so we save that and it looks something like this once second can figure out how to jeez I don't know why Windows is so picky with this come on does not want to cooperate okay maybe I'll try doing it from my consol but there we go so you see um so now they're nice and centered um we do want the button to be um to have a maximum width when it's uh at this kind of like small screen size so up at the button we will add uh the following class name so just go ahead and pause and copy this over there you go so now the button is at full width when um when it's at the uh mobile sizing but then bigger than mobile sizing it sits next to the input box um and then lastly we want to change up the way the is loading looks cuz currently we have it say searching or search but we want to add a nice little um like if I come in here and say if I search I want to have a nice little like load loading spinner so what we're going to do there is I'm just going to paste this in here instead of just the searching text I'm going to pass in this um this icon from our react icons package which I will go ahead and import up at the top so to the top of the file um I guess underneath the store yeah there we go so that's from the simp simple icons package we save that and now when you search Harry Potter And now when you search you get that nice little loading spinner now we do want to um we don't want to change we do want to change the Styles excuse me we want to change up the styles on um that the container for this table uh because personally I don't like the way this scroll bar looks I I I prefer a cleaner um simpler look so you're going to want to grab these Styles these Styles I'm not going to take credit for them this is from um the preline uh package um or not package um is it a package it's a component library that uses Tailwind so they have this uh nice little like scrolling uh or scroll bar classes um that you can grab I'll link them I'll link the link uh at the time stamp um in the description below um where you can find these same Styles so once you save now you'll see you have this o nice little slim clean looking um uh scroll bar that I'm pretty sure is compatible with other uh operating systems but I do not have a Mac so I can't verify that myself um so once you get that done the other thing we want to do is to make this responsiveness a little bit better I wish I could there we go so right now when this screen is like super small I don't I don't really want to have it um be sides scrollable I think that's just ugly I think if you have if you're in a situation where you have a table on a mobile view a mobile view then you should collapse some of the columns um and I don't think the year and the page count are necessary on the mobile view so to do that uh just head down to the table heads um actually I don't know why I added these paddings in here I think I can get rid of these so we'll just remove these and for the um for the year and the page count we're going to add a hidden class so this will be hidden until at it's at the small break point then it'll be represented as a table cell so when we save um oh so we also need to do that down here um where the the table cells show up as well so let's uh see it was this one and this one paste those there and there we go so now you'll see that when you're at the smaller size you only see the the title the author and the add button so we're almost done with the uh table restyling um couple more things we want to do in the table body um let's just add a overflow y um that way like it's always um like this is going to come in handy when you have shorter screen sizes like on a mobile device um it'll just um it'll keep it nice and constrained um because we're going to add a drawer later um the other thing we want to do is down in this start your search uh thing so if I uh remove the content over here I I kind of want this to look a little bit cleaner um so what we'll do in that case is uh for this P tag we'll just add some classes so class name uh text Gray 600 in light mode and then dark mode it'll be text Gray 400 I guess um and then last thing we want to do is actually move those results down here so we had commented that out earlier I'm just going to go ahead and cut this and then I want to say it was right underneath this div um we'll paste that in there whoops uncomment that out and replace some of these Styles so the outer uh div instead of the margin top two we're going to add this uh Flex container styling um then inside of it we're actually going to do a little bit of changing little bit of cleanup if you will so we'll add a div in here and then inside there we'll add a P tag with small text uh text Gray 600 and when it's dark We'll add text Gray of 400 oh not $499 there we go and inside here we'll paste back that total results and now we'll just do a um uh quick little modification to how the um start index and the end index show up I don't I don't like it when it's just like standard so like if I save and I run this see like I want to kind of bold um those numbers just because it kind of looks tacky the way it is right now um so we'll say oh and then we also want to add a um we also want to change the total results to be a turny operator so I'm just going to go ahead and do a quick replace like so so you'll see the total results is now a Turner operator and we have it showing there's a span where the font um changes to semi bold so you see the one out of 100 really stands out a little bit more out of that and um this actually should be showing nothing there we go so zero results so if there's nothing then it's zero results um so now if we look up Harry Pot Harry po then searching searching searching there we go so there's our results um so I think we have one more thing to do which is to um really spruce up these buttons down here because they look terrible um so we already have our uh disabled styling um but we need to H we need to add some add a little bit more Pizzazz over here so let's say this uh div down to here we'll cut that and paste it inside of um that div that we created earlier save that and now yeah looks a little bit nicer um let's just clean some of this up so we'll get rid of this um margin top um nonsense over here so we'll just say inline Flex Gap X2 save that and um I believe we can actually get get rid of this page um just because it's not super necessary so get rid of that um now last thing we have to do is add some icons so we're going to be importing um let's see I think these are from the SL uh react icons package so import these um left and right arrows copy those and back down here we'll replace the previous and next buttons with those icons and we are going to add class names oh not class names class name of size 4 oh gosh and this is the new um this is part of tail win's new um latest version so instead of having to type H4 W4 I can just type size 4 Once there we go so we save those and wow that is backwards so let's replace those so um this is supposed to be left and this is supposed to be hello right save there we go so now let's go and clean up the um the list a little bit um get rid of this import react statement at the top and we're going to need a few icons so I'm going to grab these and paste them um underneath here so we're going to need those icons from the react icons GI package and we're also going to need a new um thing from the shat CM package which is the tool tip because we want to have it where when you hover over these buttons we wanted to tell you what they do because we're about to replace all these buttons with icons so icons I think are a little bit more mobile friendly and they're a little bit more um require a little bit more reading which is ironic uh you know but we're going to need the tool tip package um so that way when we hover over it it tells you what it does and to do that we are going to copy this uh CLI statement paste it no oh there we go hit enter and then once that Imports we will copy over these import statements and I don't know why this is taken so long but while it does what it does we're going to um there we go okay it's good so we'll scroll down um to where is it card there we go and let me actually hide the terminal because that's in my way um so what we're going to need to do first honestly before I start cleaning this up is I want to style up these cards a little bit more because they kind of look like trash We'll add in these classes so what this is going to do is this is going to reset the uh border rounding um or the Border radius excuse me and it's going to make it so that the first item in the list or the first item in array has a margin top um of zero and then it's also going to have a um the the the first item is also going to have a rounded top um or a border radius on the top uh side and the last item in the array is going to have a um uh a border radius applied to the bottom side so when we save that you'll see that it looks like uh they're rounded on both top and bottom but that's because because these are not technically list items if I go down to the done section you'll see that those Styles get applied here and that's the desired Behavior right because these are meant to be draggable things so it makes sense for them to have rounded Corners top and bottom but these are not these are individual um these are items in a list that is not meant to be dragable so uh because they're connected we kind of wanted them to have those square corners at the bottom uh now let's go ahead and start adding in these uh these tool tips and these icons um so under the let's see how do we want to do this so we want to add a tool tip to every single one of the buttons so it'll look something like this right inside the card footer around the first button we'll say tool tip well you know what we're going to uh here I'll create them first and then we we'll apply them as wrappers um so the next one we're going to do is tool tip trigger oh gosh tool tip trigger and we're going to set the tool tip trigger as child and what this will do is it'll make it so that um whatever um it's child will be essentially replacing this element um and I I'll show you what that looks like in a second uh the next thing that we're going to want to do underneath the trigger is we're going to want to add the actual tool tip content so I'll say tool tip tool tip content like that and um I guess I'll put uh change me in here CU we're going to use this as a wrapper so uh to apply these as wrappers I'm going to highlight these two and copy or sorry highlight these two and then click highlight or control click highlight these two so now I have both of these highlighted contrl X so now I have two cursors and then around each one of the buttons I'm going to control click control click paste and then underneath every single one of the buttons we're going to do the same exact thing or around excuse me every single one of the buttons so control click control click paste same thing down here control click or I keep saying control click when I'm not doing that bro stop until tell a sense okay I swear it needs a delay it keeps like shoving its uh its uh popup in my face while I'm trying to click on things control click control click paste and we save but it's not going to work and the reason it's not going to work is because in order for the tool tip to actually be used we need to apply the tool tip provider around anything that is going to be using a tool tip um I think that I am so lazy so I'm just going to copy this whole import statement I'm going to remove the tool tip Provider from this component and instead under app I'm going to apply it there so I'm going to reimport these and I'm just going to apply it around the book list because that's the only place that we're going to use it um but if you end up using the tool tips and other parts of the app you might want to move it around well yeah this is fine um for for our purposes like I said it goes around everything that you wrap it around in our case we're only using it around the book list there you go so now that error is gone so you'll see tool tip change me tool tip done and the tool tip around remove so let's just go and um actually add some real uh content around the tool tips and so sorry I lost my Trend thought so under remove um we'll just say uh I don't know delete from my reading list um under the in progress we'll say Mark as currently reading um underneath this one we'll say uh instead of backlog back backlog is kind of ugly so we'll say Mark as um for later and then down here at the done we'll say Mark as done save that so now highlight over in progress we'll say now it's in progress um so I do want to get rid of the text in between these and I'm just going to paste in these uh icons so around the delete um because I'm sassy I'm going to add the burning book uh icon so there you go it's uh you know just going to burn that thing away very uh very Gus conik so we save that one um this one's just the uh book with a mark uh book with a mark a book Mark um and then we'll add I don't know the icon that made sense for the backlog like for the later was like a book pile so like this is like the books the stack of books that you're about to read and then what made sense to me in terms of like what's already been read is is um a bookshelf because I feel like if you're planning on reading things that like are for later you're just going to have them in a stack and if there are like things that you're done with you're just going to well it was nicer than putting in the waist bin and besides the waist bin sounds like yeah I don't know maybe I should put a library or something I didn't really think about it too much but yeah so if you think of better icons go for it um so last thing is uh these headers look like garbage so let's uh clean those up a little bit um yeah so on uh these headers I'm just going to replace the styles for them um like this so just going to copy or highlight this control d a few times and then paste in these Styles um so I don't they're just a little bit nicer and I want to also uh because I believe in like the intuitive part of like UI development like where like if you highlight over this this uh or not not this sorry but if you like these icons they're very like subjective right like I just explained what they are to you but you know unless the person hovers over them um and looks at the tool tip at first glance you don't really know what they are so I want to also add these um these bookmarks next to their respective uh headers I guess so um for the first header which is the in progress I'm going to actually change in progress to currently reading and we added the icon for the book Market over there um the next one is for later and for later I actually did make the icon a little bit bigger because it's a weird icon um so hello oh I don't have anything in that section let me move something there okay there we go for later so that was weird I was had a brain fart for a second um because of the way the icon is structured it was like weird um when it was a little smaller so I didn't make that one a little bit bigger and the last one is done um still done um for this one again it was a little bit weird so I had to like add some padding uh to the bottom to make it look in line with everything else so there we go um so those are our um icons so I think that's yeah I think that's it for our list um so let's just try to add some more things in here so we'll say um actually you know what I'll go ahead and add some like placeholder uh stuff because I did kind of do that in my own um implementation and figured I'd keep consistent with that so in my um and you can do this yourself if you want uh in my uh store or in your store if you want U I'm just going to paste in these initial books um it's not assignable to type string I'm wondering why it's doing that what did I oh oh I'm a silly goose I made the the publish here a string it's supposed to be a number and number of pages that a string yo I'm tripping these are supposed to be numbers well I guess that uh that whoa cannot find number oh okay we're doing all kinds of tripping y'all gonna have to forgive me the brain fog is killing me okay there we go so now I'll um down in my load books from local storage instead of initializing my books as an empty array I'll initialize them as initial books which is what I just added in there so there it is if you guys want to actually copy it uh just a bunch of pre-written these are all accurate to the um to the API I just I pulled them and saved them um earlier so just some like sample data so now if I go and I like clear out my uh my um local storage and refresh real quick there you go we have all those um default uh excuse me the yeah the initial books um the default store I guess you'd say so let's see I believe that is it I just wanted to play around with these so you can't drag these around but you come over here these tool tips are all working we'll mark the Return of the King is currently reading um psych The Return of the King is actually not currently reading we're going to move it back to for later and you know mess around with the reordering everything is looking real nice and snazzy so there is a um there is a new update to the shaten um package that I wanted to um I wanted to incorporate in this tutorial and that is the new drawer component specifically he has this new like responsive drawer dialogue that I believe I showed in the in the um demo earlier so if I open up this dialogue and I resize you'll see it pops up as a drawer which is super nice originally I had done this manually um with like headless UI and oh my gosh it was so much tailwind and so much extra stuff but this is like since we're already using chatan might as well benefit from it you know what I'm saying that's the beauty of these components just get to grab them use them do what you got to do with them all right so let's go ahead and use the CLI to uh import these um so we'll go to where there it is um so grab that snippet go back to my vs code open my terminal paste that in there wait for it to install bada bing bada boom and um I am just going to uh I hit up to go into my history so I'm just going to do dialogue so that I can import dialogue as well because I'm 99% sure it's the that that is the command yeah um so in this drawer example I'm actually going to grab wait what oh that's right that's right okay sorry I was confused with the code so I'm going to grab this and in my book search um underneath my book search component I'm just going to paste this down in here and I'm going to get rid of the um the profile form uh because we don't actually want that and let's see um I'm going to get rid of the footer because we don't really need that we're going to need that eventually but not for now um and then we also got rid of the uh profile form um what else so we have drawer cont content oh so in I don't know what I just did so in here we're going to be using this as kind of like a wrapper component so we're going to pass in a uh children um array down here and here I'll say search um I don't know I'll do for edit profile I'll just do add a new book and the way this one's going to work is like it's uh it's going to query um it's going to use this hook which I had to dig through Shen's um code to find um it's going to use that hook uh actually let me go ahead and paste that hook in here so say use media query. TS and um I'm just going to find it and paste it real quick okay so go ahead and copy and paste that this this is from his source code I can find a link um in his GitHub and I don't know if it's a dude actually their GitHub I don't know if it's a dude or a lady or not um so Shad Cen whoever Shad Cen is um this is from their get repo so you can find here on your own or I'll try to find in linking in the description um so you're going to need this hook and all it's going to do is uh whoa oh wrong file there we go all it's going to do is just basically figure out like hey my um am I at the 768 pixel break point um which is what we're calling a desktop so if it is desktop then we're going to render a dialogue if it's not desktop then we're going to render the um the drawer so let me just finish this up real quick so we're going to yeah we don't we don't want this um dialogue form thing we're just going to say children go here um which we need to pass in actually and we're going to rename this from draw dial demo to just search dialogue and this one oh gosh I hate when it's defined as a function just something that irks me one of my pet peeves you know um there we go I like using error functions because they're harder for me to type um and inside of our props we'll pass in the um children which will be um of type children react. react node uh so I think yeah um I don't like this uh I don't like what he did here so I'm going to change this to Max width large um or sorry xlarge and I think that's fine um dialogue trigger is fine and let me just double check something else yeah I think that's good so now I can save this I think I can save it yeah uh I do need to get rid of this extra button and I'm not using CN so I'm going to get rid of that and then for use media query I didn't name it that way I don't know why um shaten names names their names files that way so just going to say use media query I don't I don't like Kebab case I don't know why people use that um it is what it is though so well I'll get rid of drawer close but I'll keep drawer footer CU I I will need that in a second later um and I I'll explain why once we get to that point so uh we're going to use the search dialogue actually um as a replacement for where it is currently in the app so I'm going to get rid of the U book search um from the app. uh TSX and that includes over there and then I'm going to add it to well let me save first uh and also let me hide my terminal it's getting my way um and I'm going to head back to book list and inside a book list um where should I add this uh hold on let me think for a second so we're going to actually add this as a oh as a button somewhere dude I have too much stuff in here but yeah there we go so we're going to add this next to our uh my reading list um heading and we're just going to say this is uh it's G to be a div or a div with a height of full so height of 100% And in here we're going to uh import that search dialogue which I didn't even export silly me export there we go so say search dialogue cool and then uh remember how we said we're going to render children in there so we're going to pass in the book search uh table and this is so that way we don't have the table sitting um inside of our UI all the time this way it's hidden inside of a dialogue which is conveniently something that resizes into this drawer which I think is super nice so now we look up Harry Potter search results close and we can have a good time no big deal so uh yeah it's just something to add a little bit more responsiveness um I think it's uh I think it makes for a better ux cuz you don't always need that table up there really you want people to like immediately go to their list and then if they want to add a new book well there you go um nice thing is because it's mobile responsive let's go to the iPhone SE we add a new book I don't know I just love this UI so much so we say Harry Potter and there we go um yeah so that's it for that oh wait actually that it that is not it for that actually we need to add some stuff so um just a little bit of spacing because I don't like having the button um underneath it when it doesn't need to be um so when it's like this big it doesn't make sense for it to be right underneath it so we're just going to add a um a div real quick div wrapper which will look like that and we'll copy and paste this content in here so now when we save it the button appears on the same line but on mobile they stack vertically all right so so we're in the final stretch now let's just do a few um tweaks to our Styles um so I do want to check my layout real quick and um because we're using CSS variables provided by Shad CN we don't need like to have this background white and dark background gray um on top of that like I don't want to I don't know it's this pastel blue and then these colors over here they don't really match so what what I want to do well they they do match but they uh it makes seem like the valid drop area for this is literally any part of the site and what I want to do is I want to make the entire site match this um dark blue color or dark slate color and then I want to have each one of these drop areas have its own little like sequestered box so I'm going to replace these styles with um the background provided by this uh shaten theme so when we save you'll see o that nice nice um deep blue background and I want to make the Navar also fit the style so going to head into the nav bar and going to hide this because it's taken up too much space um and then this this also because of these uh because of how everything is kind of Consolidated in the in the theming Styles in those in the index CSS um it makes it a lot easier to like read and stuff so like when I replace these you'll see wow SL with Styles that's because background the background background the background for the background I don't know why shatan chose this name and Convention um this encapsulates both dark mode and light mode so when I hit save oh there we go um I do also need to change the um the links below so we're going to change the first link to look like this so because uh I originally wrote this Navar before the new Tailwind update but because I'm using height of 10 width of 10 I can just change these to size of 10 and then I can use the uh text uh variables that come with chaten so paste that there so all I have to do is text primary size 10 P10 looks uh or not P10 sorry uh size 10 P2 um and I'm going to do the same thing down below for these icons so it's just nice having to write like less Styles and stuff kind of standardize it's not always the best I I tend to prefer writing my own like light mode and dark mode everywhere but that's CU because I have um I'm always refactoring and I'm always reusing code so it's nice to have to like not have to untangle everything in order to use it um but that's just my preference so let's head down to the theme toggle um update these Styles real quick so replace these with that save man there we go dark mode is working just fine so now we can head to um I believe it's the search we need to do some updates over here so these are going to be quick um we just head down to the um first div where is it oh gosh such a big file um not the first div sorry the second div and we're going to replace it we're going to replace these styles with these so that way we leverage um those variables so we're using the um the muted divider in instead of the uh colors that I had chosen myself and we're going to do um a similar thing with the wherever the total results are there they are um so yeah we'll replace this outer one like so so you'll see it just looks a lot cleaner a lot neater and then the last thing we'll do is we'll head into the book list component we'll go down to the uh sorry by the way if I keep sounding like I'm smacking my lips um I had bronchitis so or I have bronchitis which is also why I'm like coughing and sound like I'm um breathing from a food processor that made no sense um yeah so I have to keep that in my have to keep that cough drop otherwise I'll be um coughing my entire Longs out all over the keyboard so that is no bueno we don't want that um so let's see I think I can just go down to these uh headings over here where are they this first heading we're going to add these Styles over here oh hello there we go save that looks a lot nighter nighter nicer if I do say so myself [Music] um actually no wait wrong one that was supposed to be around these right here yeah sorry so I'm just going to hit control D twice paste those there save and I think um one last thing we got to do oh actually we actually got to do this so I realize it's kind of silly for me to put um for me to put these divs in here like this so what I'm actually going to do or sorry this these headers in here so I'm going to do is I'm going to cut because if if there's nothing in here then they won't even show up um so I'm going to cut these headers and paste them outside of their um the drag drop context so oops cop cut that paste that there and then we're going to replace the um the in the this Turner operate over here excuse me with uh this div that will contain a um a well I'll just show you so it's like a little Drop Zone looking area uh with a lighter color so we're going to do that for both um both of the drag droppable areas so both of the places that have a drag drop context which uh will include the back clog save that so now when you drag and drop these you can kind of tell like where their valid areas are and where their valid areas aren't um and then the last thing is we do need to um we do need to clean up the way the done um one looks so since yeah let's get that header out of here so we'll cut that paste that outside and then we'll replace the um this Turner operator with a turn re operator that'll contain a fallback so uh the reason I did it that way is because before when we deleted something and it wasn't there it would just be empty right but now let's say we move this remark later we'll have a nice little message saying uh some Ben Franklin quotes Rolling Stone gathers no Moss encouraging us to read let's say we finish all of our um uh things that are in the future says look before or you'll find yourself behind and so forth and so on so yeah just nice little thing to give your um give your ux a little bit more uh of that you know that juice that spark that Pizzazz you know what I'm saying okay so last just final touches that we want to do just to clean everything up for last time is uh let's head to our store real quick so say use nope why am I looking up used store it's a store um so inside of our store uh where we have our add book function I don't want to be adding um all the contents of the new book instead I just want to paste in um this object like that so that it grabs only the things that we want to save and down under the status it'll take whatever the status that's passed in from the add button because let's say you want to have a drop down and you want to add a um add to current reading or add to backlog or add to done this will be a little bit more future proof so that you can add that functionality in later so save that um let's also head to our uh um to our search uh function sorry our search component wait why is this saying weird okay I don't think I changed anything there so think we're good um so let's go back to our search now for our search I I I ran into this issue earlier where when I was um when I was on mobile the scrolling for the um the what do you call it I'm struggling here the drawer thing uh it it was really weird on mobile it's different like it looks different here than it does um on mobile devices and that that's why I encourage people to um deploy their their sites is because even if you check out what it would look like on mobile when you're on Windows Chrome that's ultimately going to look different than whatever the mobile browser is um right because it's it's actually different software so it helps to kind of be able to see it in production um so what we're going to do in that vein is we're actually going to head down to the search dialogue and I'm going to grab this content and this content and the state values and I'm going to cut them and I'm going to move them to the actual drawer component so inside of our drawer right before our return statement I'm going to paste those in there like so and I'm also going to do some um some splitting things up a little bit right so we want to kind of segment everything based on their respective areas so we know that this is the search input so I'm going to cut this div the flex call div I'm going to say const uh well I should do this before the return statement um we'll say const search input and this is going to consist of the input dialogue or sorry the input button the input component and the button paste that there um there's also the search results which is going to comprise of um basically the contents of this scroll area so we'll cut this div like so and we'll come back up to the top and say const search results equals open parenthesis and then paste those in there don't save yet because if you save you're going to like destroy everything underneath your uh your return um section um oh and before I save this actually let's quickly um in our ad area because we don't need to do this anymore we can actually just pass in um that so it'll just pass in the um properties that are or the parameters God the properties of the book object excuse me uh as well as the status and then the store function will take care of um actually persisting it as it should be that way this code is a little bit more manageable and this way you can add your um your menu button if you want so you can have like a drop down when you add a new book so you can choose like what your uh what you want to put there instead we're also going to change this ad to have the uh same uh GI book pile uh component that we used for the uh F later icon and the reason for that is just consistency that way when someone wants to add a new book instead of them having to see the word add they actually see an icon button um I'm also going to change the variant to secondary to to make it a little bit more consistent um so also link doesn't really make any sense for that kind of component uh last thing we we're going to want to do is we're going to want to separate um the pagination so we're going to say const search pagination equals parenthesis and this is going to consist of this last Flex box over here so Flex call we can cut that and we actually I don't think we need the rest of these Styles but I'm not going to get rid of them yet let me just double check something so I paste that there and now um yeah so now we can uh in our is desktop instead of the uh instead of the children we're going to pass in the um well tell you what inside of the header we're going to pass in the search input right so the um the input uh the text input as well as the button we'll go in the header and then inside the children this is where we'll do the well hello this is where we'll do the search results cool and last thing we want to add is um right before the end of the contents we'll add a dialogue footer uh so you're going to have to import that and then inside of the footer we'll pass in the search imagination like so so that way it's in the footer of the dialogue and uh this is what I was able to get to work um better than the previous implementation and you don't have to do this um it's just my preference technically the tutorial was done in the last chapter but that's okay so let's go ahead and add these last Parts um to the uh drawer so in the drawer we're going to add um underneath the description We'll add the search input well tell you what yeah so search input and then search results search pagination will go here but then we also need to import the drawer footer and this is the one that was giving me a lot of trouble um but after I realized what it was doing this ended up fixing it so when we save that now we can go ahead and save add a new book you'll see that um yeah your dialogue footer shows up the way should your search box shows up the way it should hi well um we'll say uh Harry Potter as usual there we go and um now if I go to resize this you'll see that the footer shows up as expected um so yeah there might be one or two more things that I need to do actually um so let me just review what I have real quick yeah um I think I actually need to get rid of this uh or I need to relocate all of this stuff up top wait drawer footer I'm confused oh that's weird I guess I commented it out but it's still imported above let me actually move these up because these should not be at the bottom of the pile so I guess it doesn't matter but um a little bit nicer when they're up here so I am getting a little bit of an air o hello what was that about interesting not sure what I just removed huh sorry let me undo a few things okay what is going on right now huh I think a console error let me double check this requested module book search does not have a provided export name search St oh interesting that that makes a lot of sense so I need to um I need to remove the uh search dialogue now that I technically it doesn't really exist anymore so inside of book list um wherever that search dialogue was where'd it go I'm just going to search for search there it is so we can get rid of that get rid of that save and give it a refresh still broken what is going on let's see use media query is not defined where am I using use media query oh I'm using it here okay that makes sense so let me just import it I must have uh deleted it by accident there we go there's use media query and um oh God it's importing it down here I'm going to need to cut these back paste them up top I know I know this is a really janky part of the tutorial save that oh thank God okay now Harry [Music] Potter cool that works uh book list is still giving us an error that's because search dialogue is no longer imported now we save that and I believe yeah I believe that's it for this tutorial um so yeah let just double check in my notes real quick make sure I'm not going to leave youall hanging yep all right cool so that's it for this tutorial um it's yeah nice little mobile responsive thing [Music] um I don't know what else there has to say about it uh hope you enjoyed this one and uh hope you learn something
Info
Channel: m6io
Views: 6,178
Rating: undefined out of 5
Keywords:
Id: ktuabuTFr1U
Channel Id: undefined
Length: 167min 5sec (10025 seconds)
Published: Sat Dec 30 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.