How To Build A Google Drive Clone With Firebase

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
this video literally has it all authentication databases file storage uploads permissions firebase react literally anything you can think of this project is going to cover it because we're going to create a full google drive clone and this is going to be a long video so i hope you have some snacks food a drink something to entertain you because this is going to be a long one let's get started now welcome back to web dev simplified my name is kyle and my job is to simplify the web for you so you can start building your dream project sooner so if that sounds interesting subscribe to the channel for more videos just like this now really quickly i just want to give a demo of what this entire project is going to encapsulate because it's pretty large so to get started this is just like the home screen of our application the google drive application you can see we have our folder structure up here as well as the folders we've created so i can click on new folder and we can navigate into it and you can see i can go back to the root back to new folder i can open up this child folder as you can see inside of here i have different files that i've uploaded in this folder so like image one i can click on it and here it lets me download this image and it opens it up in a new tab for me so pretty straightforward stuff if i go back to the root here click on this folder you can see that we have folders at the top here where the folders are and then align separating the separate files inside of here we can create a new folder we'll call this like new to now we've created a new folder we can navigate inside of and we can even upload an image inside of here for example let's upload this bridge image we get a nice progress bar at the bottom as it uploads and as soon as that finishes we see that our bridge image is uploaded right here there's a ton of functionality but on top of that we also can log out and log into a different user which i've just called test 2 at test.com and once i log into this user you can see that they have completely different folders they just have this single folder with no files in it so you're able to have different profiles with different folders different structures different files and all of that it's essentially google drive in a nutshell now this is an absolute ton to cover in one video so i'm actually going to be taking the code from my react firebase authentication video and using that as our starting point so if you haven't already seen that video i'm going to link it in the cards and description for you but essentially i'm using the exact code from that video as our starting point which gives us the login and log out capabilities if you don't really care about that you can skip this section and just download the code you don't have to watch the video it's not required but it is nice to be able to have that video in place so you can understand exactly what we're doing in this video so i highly recommend you watch this react firebase auth video which again will be linked in the cards and description of this video once you've completed that you should have this source code which will again be linked in the description for you to download and that's going to be our starting point also we created a firebase project in that video all we did in that firebase project was essentially do authentication so all i've done is renamed this project to google drive demo that way we have a better name and i've just deleted all the current users we had so all the test users are gone so we have a completely blank slate to start with with this project that's already hooked up to our application so now with all of that said let's just start up our application and see exactly what we have to start with we can just run npm start that's going to start up our application open it up on the side here for us here we go i'll just drag this over to the side this is the current version of our application that's loading up and over here on the left we have the final working version of our project so we can kind of compare and contrast a little bit so now that loaded up you can see we're on the login page let's just sign up with a user we'll just call them test test.com give them a generic password and we can sign them up and you can see we get directed to the profile we can update the profile if we want but other than that we don't have any functionality built into this other than the profile and the logout functionality and what we're going to be doing in this video is adding all of that additional google drive functionality on top of it and that main google drive functionality is if we log into a user here test.test.com password we can log in and you can see this is the functionality we're going to be adding so to first do that we need to make a few modifications to our existing code because right now if we look inside of our source folder here go to our component if we go to our app you can see we wrap our entire app in this container and this container is giving us this look where all of our stuff is centered in the center of our screen like if i zoom out you can see it's in the dead center of our screen we don't necessarily want that on our google drive page we only want that on our profile related pages i'm going to take all of our authentication and profile pages and move them into their own folder inside of components we're just going to call this authentication essentially i want to move all of this code related to authentication into there not the dashboard so just this code for authentication into this folder once that's done let me just save all these files that we moved so that way they show up as being changed if we refresh hopefully this will work not quite but if we go to our app you can see we just need to update our routes here right now we're importing here from private route we need to pull from authentication private route we need to do that for all of our different routes so let me just copy this over for all of our different routes that we moved that should be all of them and if we save refresh over here looks like we're missing our sign up page so if i just come up here paste it for our signup page as well now there we go that is all of our pages correctly hooked up so essentially all we've done is move some files into this authentication folder nothing real big now the next thing i want to do is take this container we wrap our router in and instead put it on each one of our individual routes that we have here so i'm going to kind of copy this code and create a new file in here called centered container.js use that rfc trick in order to just automatically generate this for us and inside this centered container i just want to paste that code that we copied make sure we close off this div and close off the container just like that and then we need to of course import container and that's coming from react bootstrap there we go and then inside of here all we want to do is just print out some children essentially we're going to be passing some elements into this our children and we just want to render them with this container wrapping around them so we're going to take in the children so essentially the way this works if we were to replace this code we could replace all of this with that centered container class or that centered container component and down here do the exact same thing now this is going to be exactly the same if we save you'll notice no differences in our output because all we've done is encapsulated that code inside of its own component but we don't want this inside of our app we instead want this on each one of our elements so here we would do our centered container instead of this fragment and down here same exact same centered container in our app we remove this centered container because we want that to be only for individual elements related to authentication so if we just go through each one of these replace this fragment with our centered container we should hopefully just move that code inside of each one of these individual components this private write doesn't really worry about it but sign up down here we want this to be centered let's do that and make sure that we import up here center to container from that's going to come from dot slash centered container and lastly did the exact same thing on our update oh it's already done here our update sorry there we go we want centered container and centered container and finally make sure that we import that so we'll say import centered container from dodge centered container so that should hopefully center everything except for our profile page because that's right now encapsulated in this dashboard component and since our dashboard is going to be essentially completely different this is our new dashboard we want to take this dashboard component we're going to rename it to profile.js change this to be profile.js and we're going to move this up into authentication then in our app here wherever we're importing our dashboard which is right here we're going to import profile instead and that's coming from authentication profile then down here we're just going to change our dashboard to our profile if we save we're of course getting some errors because we need to save this file first so if we save that you'll notice it's now here we can now change this to our centered container just like this and hopefully that should center itself there we go so now all of our different pages are being centered if we log out we have our login page centered our sign up page is centered and everything is already centered exactly as we want even our forgot password page is centered so let's just log back in as that user and now we're redirected to our dashboard which in our case is our profile now as i mentioned we don't really want our dashboard to be our profile so inside of our routing here i want to change our routing so that we don't have this dashboard route anymore instead we have a slash user route and if we do that we don't need this to be exact anymore and this can render our profile and even to make this a little better let's just add some comments all of these routes down here are for authentication these are for our profile or our user and then up here we're gonna have our google drive clone routes right now we don't have any of these routes that's perfectly okay so we have our profile routes and our auth routes now we need to do is make sure we redirect to slash user whenever we update our profile so inside of update profile right here let's just find it right here we're redirecting to our old dashboard this should be user now instead because it should be pushing to our user so now if we just go to slash user you can see if we update our profile and if we click cancel for example we get brought back here so already that's a mistake where cancel button is should be oops slash user make sure we go to slash user so if we click update profile and we will click update for example we get directed here or if we click cancel we get directed back to this profile page which is great and when we log in you can see we get directed to our dashboard which currently doesn't do anything that's fine because when we log in we obviously want to get brought to the dashboard so now we can finally work on actually new code instead of modifying this old existing code to work with our new project so the very first thing i want to do is i'll just create a new folder where all of our google drive related files are going to go and we'll just call it google drive and in here i'm going to create a new file which is going to be our new dashboard.js so if we just generate this dashboard here real quick you can see we have our dashboard and inside of here the first thing i want to work on rendering out is this nav bar at the very top because this is actually a pretty straightforward and simple thing to make and it'll allow us to get access to this profile page which has a back button to bring us back to our dashboard so to do that i'm actually going to create another separate component for our nav bar so we'll just say nav bar dot js and inside of here we're just going to rfc our nav bar and this nav bar we actually can't call navbar we technically can but if we want to import and use the navbar from bootstrap it's also called navbar and we could rename it to you know something like bootstrap nav bar like this and then we don't have to worry about these conflicts but instead i'm just going to call this navbar component and that's going to get rid of all these issues so we can just use the normal default nav bar name we also need to get our nav for navigation like i said from react bootstrap this just avoids the conflict by renaming this now here i want to use our navbar component instead of this default div i want to use a light themed navbar so i'm going to say our background is going to be light and i want this to be expanded all the way up until the small screen sizes essentially i don't want this to ever drop down to be a smaller navbar that has the triple dots where it expands because we only have one button we don't need to need to worry about that toggle ability so next thing i want to work on here is our dot navbar. this is going to be like the big font that you see on the left hand side here for wds drive and all i want to do inside of here is put the text wds drive i want to make this a link that goes back to the home page if we click on it you can see here we get redirected back to our root folder so to do that we can say we want to make this a link this is a react router link we can import that link from react router we want to get the react router dom i also need to say what we're going to which is just the root folder just like that now the next thing i need to do is actually create our nav and in here i'm going to have a link and this link will be for our profile we're going to say that it's going to be a react router link that's what the as is for this is going to go to the slash user page and inside this link we'll just put the text profile now if we save this and import it into our dashboard so we can say here we have a nav bar and this navbar is coming from our navbar component we're just going to shorten the name down to nav bar so it's easier to use just like this now we're actually rendering out that nav bar and we can save go over here refresh our page and you'll notice nothing actually shows up the reason for this is because in our app we're not actually handling this route we need to handle a private route because we want only logged in users to access this that is going to be the exact path of our dashboard and the component will be that dashboard component and that's automatically imported for us and then we just need to make sure we import dashboard from dot slash google drive slash dashboard there we go close this off click save and now our dashboard is being rendered just like we want there is one slight difference though that our profile is not showing up on the right hand side and that's because this should say expand instead of expanded and that is going to expand out to make it fill the entire width just like we want just like this now also inside of our dashboard we want to be able to render more than just our nav bar so we're going to wrap this inside of here the fragment tags we can just make our nav bar self-closing because it doesn't really matter there's nothing inside of our nav bar and the next thing i want to render out is a container which we're getting from react bootstrap up here i want this to be a fluid container so it takes up the full width of our screen this is where all of our content is going to go inside of here so if we save you can see we have our content and it's filling the entire width if it had more text it would go all the way to the right side of our screen instead of being scrunched down only in the center of our screen like a normal container would do so now we need to really think about what the next logical step is now that we have our dashboard set up if we go over to our current working example you can see that we have our breadcrumbs right here we have an add file button an add folder button the view of our folders as well as the view of all of our different files and since in our current application we don't have any data saved so we have no folders and no files it really doesn't make sense to work on displaying out our files displaying out of folders or displaying out our breadcrumbs it makes more sense to work on these buttons for adding a file or adding a folder and out of those two you need a folder to add a file to so we're going to work on adding our folder first so we're going to work on this add folder button first and then from there we're going to work on everything else so to do that let's create a separate component for that button this will make sure that our code is abstract as possible and in small little components instead of being one massive component we'll call this an add folder button and again we'll use that nice rfc trick to generate out our add folder button now in our current example the way this works is pretty simple we click the button and it opens up a modal with a simple form of the close and an add button for creating that new folder so we want our button to do that exact same thing so the first thing i want to do is make this a button and i wanted to have an on click that is just going to run a function we'll call open modal and that's going to open up a random modal for us instead of using the actual button here we're going to use the bootstrap button so let's make sure we import button from oops react bootstrap just like that copy this down and our variant here is going to be equal to outline success and we want this to have a size here of small so if we save this and make sure we actually render this button we'll put a little bit of text in it just for now in our dashboard we're going to render out that button inside of our container we're going to say add folder button just close that off click save and you can see open modal is not defined so in here we're just going to define a function called open modal for now it's going to do nothing because we don't have that code yet now if we save you can see we have our button and it looks just like we want now the next thing we need to do once we have this button is actually add in these little folder and file icons and we're going to be using font awesome for that because they have tons of different icons super easy to use and they have a great react interface so if we go to justpawnawesome.com look for the react interface you can see this command right here we can run to download the three libraries we're going to need so i'm going to do exactly that i'm going to run these three different commands to download the three different libraries we need for font awesome this is going to give us all the free icons we can use the react interface as well as just the default core library that kind of glues everything together and once that's done downloading we can kind of just close out of this you can use this to search for the different icons that you need but i already know what icons we're going to be using so we don't really have to worry about searching for each one individually all we need to do is make sure we import the different sections we're going to use so the first thing that we need to import is going to be our font awesome icon this is essentially the way it interacts with bootstrap we're getting that from at fort awesome and we want to get that from the react font awesome right here then the next thing we need is our individual icons we want the folder with a plus in it we're going to use the fa folder plus icon and that is again going to come here from at fort awesome and this is from the free solid svg icon set just like that once we have both of these done we can actually render that icon so we can say we want to have the font awesome icon and the actual icon itself is going to be that fa folder plus icon close that off if we save we should get that folder icon showing up and as you can see we get that plus folder icon exactly where we want it so now with that button in place the next thing to work on is our modal we're going to need state for that so we're just going to have a state of whether it's open and we can do set open here that'll just be use state by default we want the model to be closed obviously and we of course need to get use state from react so we can say we're going to input use state from react just like that now that we have the state inside of our open modal we can just set open to true we can create a function for closing our modal and then here we're just going to set open to false it's just two nice handy helper functions for opening and closing our modal with that done we can go down and actually create our modal so to do this once again use fragments because we're going to have two different things inside of here so if we have a fragment we can now put in our modal and inside of this modal we need all of our modal code and of course we need to import our modal from react bootstrap now in this modal we want the show to be only when open is true and we want onhide to actually close our modal so let's make sure we just set both of those up inside of our modal let's just put a little bit of random text to see if this works if we click on this button we get a modal popping up with that text and if we click somewhere else it'll close out of our modal using this on hide function so now let's actually create the model itself to do that i'm just going to use a simple form and in this form we're going to have our body of our modal we'll have modal.body and we're also going to have a footer which is going to contain all the buttons for our modal so we'll say modal.footer just like that and make sure i spell footer properly there we go let's make sure we input our form up here so we can use that form component from bootstrap now inside of our body it's pretty straightforward we just need to input the name of our folder so we're going to create a form dot group and this form group is just going to be a label so form.label and it's going to be a form control so we're going to have form dot control and this can just be self-closing like that so our label is simply going to say name and we'll just say folder name to be extra clear what it is and for our control we just need a bunch of different inputs for example we know that this is going to be a text input we want this to be a required field because we can't create a folder with no name our value oops our value here we're going to set to a variable called name and then when we change this we're going to change that name variable which is again just state so we'll say set name and our name is e dot target oops set name e.target.value we can create that name up here very similar to how we created our open variable and by default we just want this to be an empty string so there's our two pieces of state and right here we're modifying that name when we type into it so if this works we should be able to open up our modal type in a name that's updating our name variable for us right here so that all looks like it's working now inside of our footer let's create our buttons so we're going to have a button here and this is going to be for closing our modal so we're going to give this a variant of secondary just like that and on click we want this to close our modal so we'll say close modal close that off now we can create a separate button but first we should probably put some text inside of here which says close and then we'll close off that button there we go our next button here is going to be very similar but this one's going to be for adding our folder it's like our submit button so we want this one to have a variant of success so we can say that this is going to be for submitting our form and also a type of submit so we know that this submits our form so now we click on this we can type in our name click close to close it or we can click add folder and that's actually going to submit the page right now we want the act to actually go in behind the scenes go to our firebase and create a record in our database instead of just refreshing the page so to do that we need to handle our on submit for our form the function we'll just call handle submit and let's create that up here function handle submit and inside of here let's just make sure we take in our event and do e dot prevent default now inside here essentially what we need to do is create a folder in the database that's what we're going to be using firebase for and then what we also need to do is just set our name back to an empty string so if we reopen our modal it'll be there with an empty string and we need to close out of our modal because we obviously don't need it to be open after we submit our form so now if we do this everything will work except for actually creating it in the database we can type in a name hit add folder and you can see we can reopen this and it's going to be completely cleared out for us that's all working the only step left is obviously the most difficult part of connecting this with firebase now in order to access firebase we have this firebase.js which right now exports our authentication we could come in here and just say export const firestore equals app.firestore and that's going to give us access to all of our database related stuff but this is a lot of information to give the user so instead of exporting this firestore what i want to do is actually export just part of it we're going to export a variable called database which is going to be a slightly dumbed down version of our whole firestore object for example if we want to access our folders of our database that'd be our firestore dot collection we want to get the collection that contains our folders that's what we're going to call our collection of all the folders so now we can't access everything related to firestore just our individual folders and since we know in the future we're going to have files we could create a object on our property on our object called files and that can access the files collection inside of our database it's going to be really useful for just making it easier to work with our database as a whole so now in our add folder button i could come up here and i could say import database oops database i could import that from dot dot slash and i want to get that from again going back one more level and we can go to firebase just like that now we have access to that database as we can see here app.firestore is not a function and that's because we haven't imported it up here so let's make sure we import firestore now hopefully that error should go away if i just refresh the page let it load for a second and there we go the error is gone so now we have access inside of here to our database we can go and say database dot folders dot add this is going to allow us to add a new folder based on the object we passed to it so we could say name for example is our name now we've created a new folder with that name so in order to test that this works let's just create a folder we can just come in here we can say test folder hit add folder everything appears to have worked no errors happened so if we go over to our google drive demo and we come over here to our cloud firestore section we click we should see if we create a database and just make sure we say we're going to start in test mode so we have access to everything hit next and it's here we just want to say our cloud location that's fine us central click enable and now we've created our firestore what we did before technically didn't even work so we didn't have a database created yet but now if we come in here and we try to create a test folder and click add folder now if we refresh this we should hopefully have a collection called folders there we do and inside of our collection we have both of our test folders so it looks like it actually did create our folder even though our database didn't even exist yet either way though we now have a test folder created we technically have two because we created it twice we can come in here create something else new test folder oops new test folder hit add folder come over here and we should hopefully see if we just do a quick refresh we now have another object in here called new test folder with that name and our two old test folders just like before so right now we were able to create these folders with names but it's not super secure anyone can create a folder anyone can access a folder we don't know who the parent of this folder is we don't know what's in the folder really we don't know anything about this we want to save some additional information one thing that would be really nice to know is what is the id of the parent folder so we kind of want to save a parent id we also want to save who created the folder so like the user id would be really useful it'd also be useful to have like a path of the parents of the folder so that's something that would be useful to have then finally it'd be really useful to know when these folders were created so like i created that timestamp would also be really useful right now we only have access to the name the user id is luckily really easy to get because we have this context with all of our auth information and here we can just import use auth we want to get that from our dot dot slash context oops one more step back then we can get the context and we want to get our auth context and in here we can just say current user is equal to use auth and that is a function now we can take our current user all the way down here we just say currentuser.id is our user id and actually this should be uid just like that so let's just comment out all these other lines real quick coming out the path comment out the created at and now if we save this we should hopefully when we create a folder have our user id saved there as well so let's just clear out this collection real quick just so we don't have any of those old pieces of data lying around and now let's create a new one let's refresh this see if it's still working looks like i had an error up here excellent put a parenthesis right there refresh this there we go add a folder call this one test click add and now inside of here if we refresh we should have a folders collection and inside of here we have a test and the user id is the user id of the current user we're using so now we can actually distinguish who the user is that created the folder and only show users folders that they themselves have created or that they are working on or that they're editing now the next thing that's really easy is actually this created at time stamp this is something we can get from firebase itself because we could pass up our own timestamp but firebase has a really unique way of being able to create a timestamp when the data actually gets to the server where it's saving it at our database to do this let's just create another function in here called get current timestamp that's just going to be equal to firebase.firestore.fieldvalue.servertimestamp essentially this is a function that we can run and it's going to create a value that is going to be the server timestamp at that point so right here our git current stein stamp is going to be this function that allows us to create a timestamp for the server so inside of here we can set our created at here to database dot get current timestamp and that's a function so now if we save this and let's just create a brand new one we'll call this whoops test two write that come over here refresh we should hopefully have another value for our test two right here and it has it created at which is the current time that i'm recording this january 19th that's pretty straightforward now the next two things our parent id and path are both going to be linked to each other because we need to have access to whatever the current folder we're inside of is and right now our application doesn't have any idea of current folder or anything to do with folders at all really so inside of our ad folder button we need to pass it the current folder and this current folder is going to allow us to do the parent id because that's clearly just our current folder dot id because we're creating a new folder inside of the folder we're currently inside of path is something we're going to come back to in a little bit so don't really worry about that the only other thing we need to do is set up a simple little check here that says if current folder is equal to null just return because we can't create a folder if we're not already in some type of folder whether that's our root folder or like this or if we're inside of a custom folder that we've created ourselves either way we need a folder to be able to create a folder inside of it so how are we going to go about accessing this current folder we could do all of the logic inside of our dashboard here but again i want this to be more about presentation and i want most of the logic to be separated out somewhere else so i'm going to create a custom hook instead of a folder called hooks and this custom hook is going to be all the logic that we need for actual folder itself so we're going to call this use folder dot js and make sure that this hooks folder is inside of our source that's why it's right next to our context here and we can have an export la function called use folder inside here is all of our use folder code so inside this use folder i essentially want to take in a folder id oops make sure i spell folder correctly and by default this folder id i'm just going to set to null if they don't pass anything in the main reason for that is that firebase doesn't really work very well when you use undefined it doesn't really like undefined so if we have null as our folder id by default then it's going to work while undefined will throw us a bunch of errors that's why i'm just sending it to null by default here instead of using undefined and now what i want to do inside of here is track all the state related to our folder itself and since it's going to be fairly complex i'm going to use a reducer for this and if you're not used to reducers i have an entire tutorial on the use reducer hook i'll link up in the cards and description down below so essentially i want to create a state and a dispatch which allows us to modify our state and it's going to be using reducer so we'll say use reducer just like that and of course i cannot spell user producer there we go make sure that we import use reducer we'll say import use reducer and we're going to get that from react just like that and inside of our user reducer we first need to pass it a function which is going to be our reducer we'll define that up here and then what we also need to do is pass it our default state and our default state is going to contain our folder id it's going to contain our folder object which we're also going to pass in here and we'll default this to null as well and then also we're going to have our child folders and our child files and our child files in our case is just an empty array by default and same with our folders that's going to be an empty array because we don't have any data yet this is going to be our default state we have our folder id we have our actual folder itself as well as our child folders and our child files right now we're really only concerned about the folder id and the folder itself now the first thing i want to do is whenever our folder id or our folder itself changes i want to actually reselect our photo folder essentially reset all of our default state so i can just come in here i can just say use effect make sure that we import use effect up here and inside this use effect i want to run this set of code i want this code to run every single time either our folder id or our folder changes this is going to dispatch an event over to our reducer up here which is going to take in our state in our case this is our state and then we also have our type and our payload that we're going to be passing in as our parameters our dispatch is going to pass in what our type is and this type right here is going to come from something we're going to just create a variable called actions const actions is equal to and our first action is going to be called select folder this is happening anytime we select a folder so here if we click on a folder we selected it click on a breadcrumb we selected a folder that's what select folder does essentially resets all the information to our use folder and this is just going to have the string select folder the reason we're using this object is it just makes it easier to make sure we don't have any typos so actions dot select folder then our payload is going to contain information for our folder id as well as our folder itself and essentially all we're doing is anytime this folder id or folder changes we're retelling our code to reset itself we want to reset back to this initial state here so if we scroll all the way up into our reducer we can put a switch statement that is going to switch on our type here and in the case that we have actions.select folder what we want to do instead of here is we want to turn a brand new state object the state object has our folder id equal to oops equal to our payload.folder id our folder is equal to our payload.folder our child folders files are empty and our child of folders are also empty we just reset all of our data to the same thing we had down here also i'm just going to set up a default case down here we're going to just return our state itself so which just if we use an action that doesn't exist we're going to return our default state that is the bulk of our reducer for selecting a brand new folder and the next thing i want to do is what happens when we pass in just a folder id but no folder because right now the reason for this folder is so that when we change pages over here for example from our root to our new folder we can pre-populate things like our bread comes as well as the names of different things and we don't have to wait for our folder to load because right now we're just navigating to a new page with the id and if we didn't have this folder object being passed along all this breadcrumb information would be hidden until our folder completely loaded itself so this just gives us some information about the folder without giving us all of the information about the folder what we need to do next though is make it so that when we have our folder id we can load all the information about our folder and get all of the details this includes the child files as well as the child folders and not just details like the name of the folder so to do this we just need another simple use effect we can say use effect and this use effect is only going to change when the folder id changes because this is just going to update this folder variable from our folder id and that's just any time that we pass a new folder id to use folder this happens a lot when we're changing to a different folder a different page or if we type in the url manually for example so inside here the first thing i want to check for is if we have a null folder id so if folder id is equal to null then that means that we aren't in a folder we're in what you would call the root folder because we're on the dashboard of our page we don't have a folder id yet as you can see we have folder ids in our url but on the root we don't have a folder id because the root folder is really a made up thing there is no root folder in our database it's just something that we've created to allow us to add folders to this root folder it's just the nothingness essentially so here i want to return our dispatch because i want to exit out immediately i don't want to do any other code and in here i'm going to have a different type and this is just going to be for updating our folder so we're going to call it exactly that update folder and this payload for this is just going to contain our folder object which is going to be something we're going to call our root folder we're going to create this variable in just a second so first we need our update folder action which is going to update our folder and inside of here we need a case for actions.update folder and inside of here all we want to do is return a new state object which takes our current state and it updates our folder to be our payload dot folder all it does is update the folder portion of our state now let's come in here and create our root folder object so our root folder is just an object that's going to look very similar to our folder inside of here it's going to mimic our database but it's going to be essentially a fake object a fake folder so this will have a name which is root just like that it'll have an id which in our case is null because it doesn't actually have an id in our database database and our path is just going to be an empty array because there's nothing before this our path kind of indicates things that come before and right now our path is an empty array because there are no things before our root folder it is the root of our application so now we've actually created some system that can identify when we have no folder and it'll save us as the root folder in our case to actually test this if we come down here and just return our state and then we use this use folder hook up here so we can just say oops const state equals use folder make sure that we import use folder up here and right now we're passing it nothing because we don't have an id to worry about so we're just going to pass in our state let's just see what this state looks like we can log it out come over here inspect our page not view source make sure we inspect our page but the console and you can see we have an object this object has empty child files empty child folders no folder id right now because our root doesn't have a folder id and it has a folder object with a name of root our id is known our path is an empty array that's exactly what we want our current folder is a root folder because we don't actually have an id of a folder we're currently on so this is exactly what we want we can actually pass that folder to our add folder button let's just destructure this a little bit we're going to get our folder out of here we're going to pass that to our add folder button as the current folder equals our folder now we have access to that current folder itself inside of here and we can hopefully see that our parent id for our next folder we create is going to be populated as null because we don't actually have a folder so if we pass in just a random name come over here we find that element and you can see the parent id is set to null and that's because our root folder has a null id so now the next step is if we go back to our use folder what happens if we actually have a folder id well what we want to do is we want to access our database which we just make sure that we import up here so we'll say import database from firebase and we want to make sure it's going back a little ways just one too far firebase just like that so now way back down here we can say database dot folders we're going to get a single document which is going to be our folder id and we can just say dot get to get that document this actually returns to us a promise so we can say dot then and it's going to pass in a document we say console.log out that doc also if there's an error we can say dot catch and inside of this dot catch this would be like if you try to access a folder you don't have the permission to access one folder you didn't create for example what we want to do is just copy this exact code up here we just want to set to the folder to the root folder so if there's an error getting the current folder we're just going to update to the root folder instead so now we essentially have here a document that we're getting and then down here we have our actual folder itself so let's see if this works if we pass in an id i'm just going to copy an id this right here is our id of our folder i just want to copy this id it'll be a little easier if i just expand my screen highlight this copy it and now it's going to hard code inside of our dashboard that id this is clearly not how you want to normally do this but for our testing use cases this will work just fine let's get rid of all these extra spaces that are in there now if we save we go over to our application and we of course get cannot read property doc of undefined so if we go back over to our use folder it looks like it's saying it cannot read doc of folder and that's because it should be folders our database is called folders and there we go so if we inspect we should have that dock being printed out to us so we can see here we have this element t which contains our dock and you see it's kind of a mess there's really not that much useful information inside of here and that's because to get pretty much all of the information other than the id of the document you need to call something called the data method so we can say doc.data and call that as a function and that's actually going to give us all the data that we care about as you can see here we have our created at our name our parent id and our user id we've converted all the useless information into some useful information if we want the id we just say doc.id so really what we want to do is convert this doc into a usable format we can easily do that by just saying that our formatted doc is equal to it's going to be our id which is our doc.id and we're just going to spread out the doc.data now if i print out formatted doc this should be exactly what we want and let's just inspect over here to make sure go to our console you can see we have an object which has our created app name parent id user id and then finally of course our id this is all the information that we care about and since we're going to do this all the time i actually want to turn this section right here into its own function inside of our firebase we're just going to call this format doc and this is going to be a function and this function is going to take in a doc just like that and i just want to return the exact code we had there so doc.id and spread out our doc.data there we go now we have our format doc function which we can actually use so here whoops not here instead of our use folder instead of doing all this code we can just say format doc and that's database format doc pass it in the doc that'll do all that code for us now we inspect we should get the exact same result to the console and we do so now i just want to copy this dispatch and instead of using our root folder i just want to use our formatted folder here so now when we have an id our currently selected folder is going to be based on the folder we get from our database if we go into our dashboard and just say console.log folder we should actually see the folder being printed out now as our current folder you go to the console you can see right here our folder is being printed out just as we expect it's null for a little bit until finally the database tells us what the folder is and then it prints it out right here so now that we're able to access the current folder that we're on the next thing i want to do is access all the child folders because right now we've set our folder manually to this folder so if we create a new folder it should have this as the parent id and let's just test that we're going to call this child now if we go back over here we look at this new child you can see the parent id is that p9hf which is this manual id we set so we're able to actually create child folders so now we have a child folder inside of our main parent folder which is this folder here just called asdf so now what i want to do is render out those children folders onto our page just like we've done over here so to do that we need to again of course create a new component this new component we're just going to call folder.js use that little rfc trick to generate out of the boilerplate and all i want to do in here is pass it a folder which is the folder that we're going to render for now i'm just going to print out the folder.name because we don't really care about anything else so we're just going to print out the folder name we go into our dashboard and we import that folder component so dot slash folder just like that we can actually come down here and if we really wanted to we could just render out folder and pass it our current folder and now you can see that it's rendering out the name of our current folder and of course it says cannot read name of null that's because at the very beginning our folder is null so to get around that just temporarily we'll just say folder and this so it'll only render folders not null and there you go you can see it prints out the name of our folder that's great but of course we want to render our child folders not just our folder that's current so instead we want to loop through all of our children folders and render them so what i want to do is i just want to create a section here that if our child folders which we're going to get up here from our use hook our child folders dot length is greater than zero that means we have some folders what i want to do is render some code inside of here so inside of here i can just say i want to render a div i'm going to give it a class name of d flex and flex wrap this is just a container that contains all of our child folders and then i'm going to loop through each one of these child folders and print them out as that component but first i want to actually wrap them inside of a div and this div is going to allow me to do a little bit of styling so first thing first obviously you need to put a key on it which is our folder id we're going to have a style here and the main reason for this is just to specify a max width of course i spelled it wrong max width of 250 pixels just so it's not too wide and finally our class name of p-2 to give us some spacing between our different folders now we close off that div just like this inside of that div we can render out that folder component we can pass in our child folder as it we can rename this even to child folder just to make it a little bit more straightforward what folder we're referencing now we have a div wrapping our folder and it's going to print out each one of our child folders inside of this section of course though we aren't populating our child folders yet because inside of use folder we're just setting them up here to an empty array so we need you guessed it another use effect to handle this so use effect inside of this use effect pretty much any time that our folder id changes we want to run this use effect this use effect is going to be a little bit different than most other use effects then we're going to have our database.folders we want to do a search here so we want to say where we want to search where the parent id is equal to and we want to search where it's equal to our folder id and you'll notice this kind of weird format syntax this is the way that firebase works you pass in the property you want to search for in our case parent id you pass in the check in our case equal to then you pass in the value you want to check against that property we're checking where the parent id equals our folder id also we need to do another where check because we want to make sure we only get folders that are created by our current user so where user id is equal to our current user dot uid since we're using our current user in this effect we need to create our current user as one of the parameters that when they change we reset this entire use effect let's just save this to get it formatted a little bit better then the next thing i want to do is order this by the created add field just so they always stay in the same order that we created them at super simple that'll be nice then we're going to use something called on snapshot this is the real kicker this is the important part essentially this is going to run code every single time a new folder is created or anytime a folder is changed or edited this on snapshot function is going to run to tell us what the new set of folders that meet this criteria are so we can just create a simple dispatch here and all we need to do is tell it the type which in our case is actions dot and we're going to call this update child folders and actually instead of update we're going to call this set because we want to completely set the child folders and our payload is just going to be our child folders we can get this from our snapshot we want to get all of the documents we want to format them so we're going to map over our format doc function essentially all that this code is doing if i just expand this a little bit to make it a little easier to read i make sure i format this properly what we're doing is we're running some action called set child folders which we have yet to create and then we're taking all the folders which are these documents and we're just making sure we format them properly just like we did up here in this use effect we're formatting our document but now we're doing it inside of an array which is why it's in this map now if we come up here we can create that set child folders which is just set child folders this is going to be almost the same as updating our folder all we're going to do is say set child folders and our child folders are going to be set to our payload.child folders now of course we're getting some errors current user is not defined that's because in here we're not defining our current user anywhere so we can say current user is equal to use auth and let's just make sure we import that properly so use auth imported right there we now have our current user if we save hopefully this should refresh and work and of course it says cannot read property where of undefined i did the same thing this should be folders instead of folder and now of course all of our stuff is working as we expect now what we can do is we can say that we want to return this on snapshot and you may think that sounds really weird and the reason why is because on snapshot returns a function that allows us to clean up this snapshot so this would be like a cleanup function clean up and then whenever you need to clean this up essentially stop listening you would just call cleanup and that would stop the listening and in react whatever you return from a use effect so if we return to this it'll run this cleanup function every single time our parameters change so that way we have a new snapshot to listen to but we can kind of shortcut all that by just doing the return up here and that'll do all the work for us so anytime that these parameters change down here it's going to make sure that it reruns all this code and cleans up our old listener so we only ever have one listener at a time now with all that done hopefully inside of our dashboard we can print out our child folders we should actually have folders being printed out so if i inspect this go to the console we of course have empty arrays and we have an error it says error in snapshot listener the query requires an index you can create it here what that's essentially saying is that we need to create an index for our folder if we go over to use folder that is on parent id user id and created ad we just get rid of this create that for now there's no longer going to be that error and you can see instead we're getting new errors so let's look at these first to see what they are it says cannot write property of id of null cannot perform back state up and this is just our folder.id it's saying that there's no id for some of our folders that it's generating from this formatting of our documents so if we look at the code over here you can see child folders we're mapping over them and then here we're using folder.id instead of childfolder.id so in our dashboard let's just make sure that this here says child folder dot id now hopefully that gets rid of the errors and you can see it prints out our name child if we go back to our console we should have no errors and as you can see we have no errors and it prints out our one child object all the data inside of it that's exactly what we expect but if we go back to our use folder and we put that order by in there it's now going to stop working and that's because we don't have that index created so there's two ways to do this one way you click on this link and it will automatically create the index for you pretty straightforward or you can manually create indexes inside your cloud firestore here by clicking create index and type in all the fields that you want for our case i'm just going to use the link version because it's way easier so once that loads up i'm going to zoom this in so it's a little easier to see essentially it says the fields that we want to have an index on the scope that we're querying on as well as the collection id we just click create and it's going to run through all this force and you notice this format is not nearly as nice as this firebase format over here but it's a one-click thing and it does it for us it takes a little while to run especially if you have a lot of data so we're going to leave it run in the background and eventually it's going to fix itself and work so we can kind of just close out of that come back over to here go back to our data and if we refresh this you know we hit inspect it's still not going to work because it says that that index does not exist so we're just going to comment this out for the time being so that way we can still see our folders and then hopefully by the time we're done formatting and styling it we can add this back in because it'll have created the index by then we can keep tabs on it by over here just waiting for our index you can see the status is building right now so once that's complete we'll be able to actually add this back in so now like i said let's work on the styling of our actual folder icon because it's going to be pretty straightforward we just want this really simple format that's like a button we can click on so let's go into folder.js and here instead of having a div we want to have a link tag because we want this to be something that we can click on and inside that link tag we want to print out our folder name but we also want to have a font awesome icon of our folder so of course we need to import font awesome icon from at fort awesome we want to get the react one here and we need to import the icon we want which is just called f a folder and that's from our free solid svg icon set now in here what we can do is we can print out our font awesome icon our icon for that is going to be equal to that fa folder icon and i'm just going to give it a little margin on the right hand side of two that way it spaces itself out slightly from our folder name we save that you should see over here of course we're getting a failure it says link is not defined we just need to import link from react router dom now hopefully that should get rid of that error for us and as you can see we now have this link showing up but of course the styling is really really ugly to fix this i'm actually going to change this to a bootstrap a button instead of a link and i'm just going to use as link to set it to a link and let's just make sure we import whoops button from react to bootstrap now if we save that it should hopefully look a little bit better there we go now we can kind of change it to give it that darker style so we're going to change the variant here and the variant is going to be outline dark now if we save we'll get that dark-ish outline just like that exactly what we want and then to make it a little bit better to just finalize our styles we're going to come in here with a class name our class name is going to be text truncate and width 100 that's just going to make sure it always truncates our text for us it doesn't expand too far if our name is really long so refer to add another folder we're just going to give it a really long name here let's add that folder you can see immediately our code right here for our snapshot has automatically figured out we added that folder and populated it onto our page and also you'll notice it truncates the name if the text gets too long that's the maximum width that we set right here of 250 pixels we change this to for example 150 pixels you'll notice it'll shrink down that maximum size for us so you can really play around with this number to see how large or how wide you want your different icons to be with all that done let's come over here to check on the status let's just refresh this to see if it's finished building it says it's still building like i said it takes a little while so we'll keep that commented out for now and we can move on to the next step which is rendering out our bread comes up here where it tells us what sections we're in this breadcrumb right here also before we do that we should probably make it so our link actually goes somewhere because right now our link doesn't go anywhere so let's give it a two property and we're going to tell it that it's going to go to an interesting place this too is actually going to be going to slash folder slash and we want to get our folder id so when we click on this link it's going to redirect us to slash folder and give it an id so let's just come back over to here and we're going to click on one of these and you'll notice up here our url says folder and then the id of that folder and that's where we want to redirect ourselves to so if we go back to our dashboard we want to be able to render things that have a folder id so to do that we need to go all the way back to our routing in our app.js and create a brand new route this is going to be a private route we'll just use exact again and the path here instead is going to be a dynamic path so it's going to be slash folders slash folder id and again the component for this is going to be our dashboard we want to render the exact same component but now we actually are passing it a folder id and let me just make sure i type this as folder instead of folder id so now hopefully our page will refresh and it actually renders out our hard-coded folder so instead we want to change it to render out the folder with the id we pass into it so if we go all the way back to our dashboard here i want to get this url parameter and we can get that using react router so react router has this really nice thing called use param which we're going to import use param it's actually called use params sorry from react router whoops router dom so here above our use folder hook here we can say that we want to use param to get our folder id use params essentially we just call this function and it gives us all the parameters as an object we're destructing that because we only care about the folder id and then we can pass that folder id in here to this use folder now if i save this you can see that we're redirected to that child folder and if i get rid of all of this it should hopefully redirect us to our root folder there we go if we click on this it'll now redirect us to that folder now we're inside the child folder and so on so now that we have that working we can move on to working on the breadcrumbs now to create these breadcrumbs we're going to do that inside of our container we're actually going to create a div which we're just going to put all of our items inside of we're going to have d flex here we want to align our items in the center and if we just close this off we put our add folder button inside of here we're also going to put our folder breadcrumbs inside of here so let's have folder breadcrumbs which is a component we're going to create and of course we need access to the current folder we're in otherwise we can't get the breadcrumbs if we don't know what folder we're in now we need to create that folder breadcrumbs component pretty easy folder redcrumbs.js and use that rfc trick just to generate all the boilerplate code and of course we're going to pass it in a current folder as a parameter now let's just make sure in our dashboard we import this component so we'll say import folder breadcrumbs from folder breadcrumbs and now we should hopefully get rid of this error just like that and in our folder breadcrumbs we need to of course render out breadcrumbs and we'll use the breadcrumb from bootstrap to do that so we'll say red from and we want to get that from react oochstrap just like that and here instead of a div we're just going to do our bread from and we want to make sure that we close this off breadcrumb there we go so now what we need to do is essentially loop through all the folders that come before our current folder and render them out as breadcrumb items and then lastly render out our current folder as a breadcrumb item so the first thing i want to do is just render out our current folder so if we have a current folder then what i want to do is render out a item for our breadcrumb for that current folder so we can say red from dot item and inside here we're going to put our current folder so we'll just say current folder dot name that's going to render out the name and then i want a few properties here we're going to put some class names of text run kate and d inline block that's just to make sure our text will disappear if it passes our maximum width which we're going to define right now so our style for our max width is going to be 200 pixels just so we can truncate anything that's a little bit too long then finally we're going to set this to active since we want this to be the one that is currently active so we can't click on it also you'll notice it has this weird background color and this weird padding i don't want any of that so instead of our breadcrumb we can say list props we're going to pass some properties to our list and we can just say we want to pass some class names which are going to be background white and padding 0. now if we save that we're of course getting an error that's just because here that should be not an equal sign it should be in a colon and now you can see that we got rid of all those weirdness that's going on also i want to make sure that these bread crumb grows be the full size so i'll say selects grow one that'll just push everything else over onto the side like this and that's why we have our bread crumbs here and then everything else to the side also we want to get rid of the margin on the bottom of this whole thing so we can say m 0 as well that's just going to get rid of the margin on the bottom and we actually need to do that on our list instead we can say m0 here and that's going to get rid of the margin on the bottom which centers this item with our button over here you'll also notice our content is like pressed right up against the top of the screen here so instead of doing padding zero i'm just going to do padding on the left of zero that'll return the padding on the top and bottom which is exactly what we want so now it's a little spaced away from the top of the screen and that looks a little bit better just gives us some spacing right now we're rendering out just one breadcrumb for our current item that we've selected that's not super useful like if i go back all the way here hit enter you can see we've rendered our route now we rendered out the current folder we're in and again the current folder in but again that's not super useful i want to render out the breadcrumb for all the things that come before as well if you remember a little ways back in our add folder button we had this path that we were talking about the reason this path is so useful is it's going to give us a path to all the folders that come before this current folder in order this is really useful so we can render out our breadcrumbs otherwise when we render our breadcrumbs we need to actually access each folder individually by id which is going to be a lot of unnecessary calls to the database and it's just not worth it so instead when we create a folder we're going to save the path to that folder inside this path variable to do this i'm just going to create a variable up here const path and this path is going to be by default set to our current folder dot path so we're going to get our current folders path and set that as our current path then what i want to do is if our current folder is not equal to the root folder then what i want to do is i want to take our path and i want to add in a new variable for our current folder we can say name is our current folder.name and our id is our currentfolder.id the reason i'm doing this only for folders that aren't our root folder is because like i said our root folder is like this made up thing that we've created it's not actually in the database we don't want to save this as a part of our path because the root folder is not actually a database element so now we've taken our current path we've added on the current folder to the end of that path and now we can put that path inside of the database so if we save this you're going to notice it says root folder is not defined we need to import that root folder and right now that's defined inside of use folder so up here let's make sure we export this root folder and then inside of our add folder button we can import root folder and get that from just go back a little ways you can go into our hooks slash use folder and now this should get rid of that error for us just like that now we can do is we can create a folder let's go all the way to our root we're going to create a folder called at root add this folder we go into here you can see hopefully if we refresh this our status will no longer be building you can see it's enabled so we can actually now go over to our what was it our use folder hook we can make sure that we sort by created at because now that index is built but now we can go over to our data here that new folder we just created let's find it at root and you can see our path right now is just an empty array there's nothing inside the path because that was our root folder we created so now that we're inside that at root let's create another folder called in at root actually to make it a little simpler we'll just call it child one add that folder now inside of here we can find that child one that we just created we can see here child one now has a path and that past has the name of the parent which is at root as well as the id for that parent let's add another thing inside of child one we're going to call this grandchild one now if we find that in here let's just do a little quick search for it and there it is you can see now the path has both the grandparent as well as the parent in the correct order so we can render out this path inside of our breadcrumbs and navigate between them so to do this let's go over to our folder breadcrumbs and what we want to do is we want to get our path we're going to create a variable called path we're going to set it to our current folder we're going to say if our current folder is our root folder then we don't have a path so if our current folder is our root folder our path is just an empty array otherwise our path is going to start with our root folder because essentially we're going to say we want to see if we're in the root folder if we're in the root folder we don't have a path because we're in the root folder otherwise our path will start with the root folder and the reason we're doing this is because we don't save our root folder inside the database so we need to add that manually then if we have a current folder what i want to do is i want to take our path i'm going to set it to our path that we've gotten up here and then i just want to add in our current folder.path so essentially if we're in the root folder this isn't going to do anything but if we're not in the root folder this is going to take this path which starts with root folder and add on all of our other elements to the end of it then what we can do is loop through that path so we can say that we want to go through each one of our path variables we want to map over them we say dot map we have a folder and we have an index and we just get rid of this real quick so we have path dot map and for each one we have a folder and an index inside of here i want to do the exact same thing i want to render out a bread current item and i'm actually just going to copy this bread chrome item right here because it's going to share a lot of the same stuff except for of course we don't want this to be active so we're going to remove that active class and we want to get our folder.name instead of our current folder.name and we of course need a key which is our folder.id i also want to change our width here to be a little bit smaller we're going to use 150 pixels because these aren't as important and also i want this to be a link so we can say link as we want to use the class of link that component i'm sorry which comes from our react router so we'll get link from react router just like that we're just converting our link here to use that and let's just make sure we actually return this by using parentheses here instead of curly braces go to this auto added semicolon and hopefully if we save it again says root folder is not defined we need to import root folder that's coming from dot dot slash dot dot slash and that's our hooks folder just like that now that should hopefully get rid of that error and of course you can see our breadcrumbs are being printed out but right now our link doesn't actually go anywhere if we click on this it doesn't do anything so we need to give it a two property which is going to come from our link props because we have our link as now we're passing our link props our link props here are just going to be a to prop which is going to go to that folders so you say folders and we want to go to slash folders slash our folder dot id now let's see if this actually does anything we click on at root you're going to notice it looks like it should work but it really doesn't we just inspect our page see if we have any errors we don't have any errors and it looks like of course this should be slash folder instead of folders again i typed that in correctly so now if we just go back refresh this click on at root you can see it redirected us back here click on root redirects is here but we have an error because it says current folder path is not iterable folder slash null there is no folder with that null index so here we just want to say if our folder dot id if we have a folder id redirect to it otherwise that means we're on the root folder so redirect to the root now let's save that let's make sure we redirect ourselves to the root let's just navigate down a few folders and of course here current folder.path is not iterable this is mostly because we have folders in here that don't have a path so anything that doesn't have a path we want to delete this is just old data so we can delete this let's delete the document let's see this one no path so we're going to delete it this one right here has a path that's fine this one has a path it's fine this one has no path so we're going to delete it this is just so we can get rid of all of our old data that happened before we added our path so delete this one this one has a path and then we can delete this one so hopefully this error should go away so now if we go back to our page just refresh real quick you can see of course we still get an error current folder.path is not iterable so one thing we can do is we can check inside of our use folder we scroll all the way up to our root folder we can see we do have a path here so that is correct now we can go into our folder breadcrumbs we need to figure out what folder we're currently on that is not iterable with a path so we can just say console.log current folder let's just see what our current folder is we just inspect this real quick go to our console you can see it looks like we have a bunch of errors but our current folder is just an id there's actually no document associated with this that's just because we don't have access to this folder so let's just close out of this go back to our root we essentially deleted that folder that is why we're getting that error and now we can essentially say we're going to click on our at root child 1 grandchild one and you'll notice something really interesting if i go in and slow down my network speed to be really slow we'll say slow 3g and i click on at root you'll notice that our breadcrumbs disappear and then reappear disappear reappear disappear up here it's kind of a weird phenomenon you would think that they would just stay there the entire time like if i click grandchild one it shouldn't read like disappear everything except for root and then reappear it should just disappear or should just stay there i'm sorry we can even make it really slow i have this custom preset and when i click you can see they stay gone for a very long period of time before they reappear this is something we can actually quite easily fix by instead of passing just a two property to our link we also need to pass it a state a state is essentially some piece of data you can pass along when you change your route so if i click on this child 1 or click on at root i want to pass along the folder that i'm currently in so that i can keep this route currently navigated to the correct location so here instead of doing a you know just route here i want to pass an object and the path name is going to be what we normally pass to 2 i also want to pass it some state and the state is going to be an object that contains a folder and this folder is just our current folder that we're on that we clicked on so we can just spread out our folder but i want to replace the path of this folder with a new path so i can say our path is going to path that slice from one to the index this may seem a little confusing so let me explain exactly what is going on here essentially what's happening is we're going to be passing some state information along with our route so right now we have a route that passes our id we're also going to pass state which is this object this object has a folder property which is just our current folder right here but our current folder doesn't contain the path information because if we look in one of these you can see one that has a path all it has is the id and the name so we're going to put the path on it and by saying path that slice we're taking everything from the first element inside of our array so if we have one that has multiple elements like this we're taking everything from the first element up to the current index so if we clicked on at root it's going to take everything from this first element all the way to the current index which is the root we clicked on that way it's not going to get any of the information that comes after it we're essentially only getting the elements in the path associated with the current folder that we clicked on so now if i come over here and click on for example child one check grandchild and i click on at root you're going to notice we still get that flash it's very quick but it's still there that's because we're not taking advantage of our state anywhere we need to do that here so to get the state from react router we use a hook called use location that allows us to get a ton of information but one of that pieces of information is our state and by default we want to just set it to an empty object we're going to get that from used location and then in here we can pass our state dot folder which is the data we passed along so now if i just go along here we'll go all the way to grandchild and i click i'll click child one you'll notice we don't get any of that weird flashing all the information stays here now if i click this folder we get the flash and that's because inside of our folder component we're not passing along any of our state information so instead here i want to pass an object that has a path name equal to the path name we currently we're using just like that i also want to pass along our state so we can say comma state and the state is just going to be our folder and it's going to be inside of an object just like this now hopefully if i were to click on child one you can see none of this path stuff flashes it still works just as we would expect and that looks really nice it looks a lot cleaner and it just looks better overall gives the better user experience and it's pretty easy for us to change this and make it work now before we start venturing on to the file portion because we've pretty much finished everything related to folders the next thing i want to do is work on firebase rules if we go over to this rules tab at the very beginning when we set this up we essentially said we want this to work in development mode and that just allows us to do anything literally anything in the database as long as the timestamp is before a certain date essentially it allows us to do anything for a certain period of time and then it'll cut us off instead what we want to do is we want to set up specific rules for all the information inside of our database what i want to do is i want different rules for reading writing updating creating and so on down here i can say i want to allow read if certain things are true so i want to loud read if for example our user is authenticated so we're going to create a function called auth and i want to make sure that our user matches so we're going to say matches user we're going to pass it in the data for the call that we are doing to this read so let's create these functions up here we can say we have a function called auth and we also are going to have a function called matches matches user this is going to take in our data so instead of our auth function this is the more straightforward one we just want to return if our our data has an auth so we can say return request dot off i'm going to make sure that's not equal to null so if we have data and authentication this will return true if someone's logged in if they're not logged in it'll return false so we can say is someone logged in okay also is this user that's logged in matching the user associated with this data if you remember in all of our data if i just publish this real quick of course we're getting an error we just need to make sure return here we'll just return true for now now if i publish this it'll let us go we go over to our data you can see every single one of our pieces of data has this user id so we want to check to see if the data we pass has that user id so we can say if we have our request.auth.uid this is our user id if that equals our user id of our data then return true otherwise return false so now we're only allowing a user to read data both if they're authenticated and if they also are the user associated with that folder now we can publish this hopefully it all works there we go if we refresh over here we won't notice any changes but if for example i were to log out so i go to my profile i just do a quick log out and i come in here and i type in a new user so we'll just sign up test 2 at whoops at test.com give them a generic password sign them up so now if we try to access a folder from our another user so if we just go back to our data we just copy a random folder id and we try to go to that exact folder so we say slash folder slash that id hit enter you're going to notice we're actually redirected back to the root folder and that's because in our code we go way over here you'll notice and it's in our folder scroll up to this very first our second use effect sorry what we do is if we catch an error then we update our folder here so let's just get that error object and we'll just say console.error our error and now if we inspect our page over here we should have an error being printed out the console says missing or insufficient permissions so we tried to access a folder the user that we are currently signed in as does not have access to so it through an error and by default we're catching that error and redirecting the user back to the root folder essentially saying you don't have access to that folder so that's a really great catch that we've implemented by doing this allow read here to make sure they're both signed in and match the user that we're currently using the next thing i want to do is we'll just come back here log out of this current user and we're going to log in as our actual user test.com password so we have all of our information the next thing i want to do is allowing create and the first thing i want to do is i want to make sure that you're signed in so if auth and i want to make sure that you also are matching the user of the thing you're trying to create and instead of doing resource.data what we want to do instead is get this information from our request so we can say request.resource.data this is going to be the information we actually pass up to our request so we can just publish this real quick and now what this is saying is we can only create information we can only create a folder if we're both logged in and our user id matches the user id we are saving to that folder so inside of our add folder code we just expand this so it's easier to read down here where we're setting our current user id right here we're making sure that this matches so if we were to change this to something else we're going to get an error when we try to create a folder so if i try to create a folder here add it you're going to notice it doesn't actually get added if i go to the console we're going to get an error right here that says in submission or insufficient permissions because i tried to create a folder with a user id different than my user id if i change this back and i now create a folder you can see it added it just fine and we're not going to get that error in the console and that's because our user id matches the user id we passed up with that folder so that's awesome we now have read and create permission setup where only the user that is accessing the data can read it and only the user that's creating the data can actually create it this just adds a lot of security to our application so now with all of that done we can finally move on to actually adding files instead of just creating empty folders so let's create a brand new add file button.js component do a little rfc trick and inside of our dashboard let's make sure we import that so which copy this is the add file button and from add file button there we go and down here we can just have our add file button pass in our current folder which is equal to our folder and close it off so now we have our add file button which right now is completely empty not doing anything so we should actually make it do something first thing it accepts a current folder and inside of here what i want to do is i want to create a label which is going to be a little interesting the reason i'm using a label is that i can automatically click on the input file button and this is just going to allow us to create a custom file input so i want to also create an input for inputting that file so we're just going to use an input the type equal to file and an on change which is going to be equal to handle upload which is a function we're going to create up here function handle upload i'm going to take in that event parameter right now i'm not going to really worry about this too much and then also lastly inside of here i want some styles i essentially just want to hide this thing so i'm going to set the opacity to zero i want to set the position to absolute just like that and lastly i want to set the left to negative 9999 pixels essentially just make it completely off the edge of the screen invisible completely blank it does not exist to the user what we're going to do is interact with this label which i want to style to look a lot like a button so we're going to say button outline success button small margin is going to be zero and our margin on the right is going to be two just to push it a little bit away from the side of the screen so now if i save that you can see we have a button which is empty for now let's just add a font awesome icon oops make sure i spell it correctly so it's font awesome icon and the icon inside of here is going to be equal to fa icon file upload just like that make sure that these get imported up here just like they have now if we close that off save it again we should have the correct icon just like that and actually what i want to do is i want to swap the order of these buttons just like that now there's spacing between them just as you can see here so we have upload file and upload this folder and if i click this upload file it's going to be exactly the same as if i clicked this input which we've created here but the input is completely hidden based on these styles but since we wrapped it in this label it associates it with this input so when we click on the label it's going to do the on change for our input here so now in our handle upload i want to get our file which is just e dot target dot files i'm going to get the first one because we're only doing one and if for some reason our current folder is equal to null or our file is equal to null for example they just don't choose a file then i just want to return i don't want to do anything else now the next thing i want to do is actually upload this file to our firebase and in firebase we have something called storage here where we can upload all of our data to so i want to upload it to our firebase storage now to do that we need to modify our firebase here so we want to import firebase storage i want to export a variable which is going to be called storage which is equal to app.storage just like that same thing as our auth same thing as our firestore up here they work exactly the same so now inside of our add file button i can have access to that storage now the first thing i want to do is to determine the file path essentially the folder path for this so we can say const file path is equal to this is going to determine if we have a path so currentfolder.path.length if that is greater than zero then what i want to do down here is get our current oops current folder dot path i want to join that on this slash symbol essentially i want to take the names of all of our folders and concatenate them so our file path has all those folders in it then at the very end i want to take our file dot name and add it to the end so we have all of our folders leading up to our files name itself otherwise if that's not the case i just want our file to be in file.name so essentially our file path here if we have a set of folders essentially a path i want to make sure that that's the beginning of our file otherwise just do the file name as the file path then down here i can create what's called an upload task this is how you manage uploads inside of firebase this is just going to be storage dot ref this is going to point to the location where we want to upload this so this is going to be uploaded in slash files slash we want to get our current user.id which of course we need to import our current user we'll do that in just a little bit and our file path again needs to be string interpolation so here essentially all we've done is we've used a root folder called files for our individual user we have a new folder and then our file path which we created up here that's where we're going to be saving this upload task to we want to put this specific file in that location so we've created an upload task which is at this location and we're putting this file inside of there so in order to get our current user let's just make sure we input use auth oops use auth from dot slash and we need to go back one more into our context slash off context and then here response to current user equals use auth and make sure we wrap this just like that there we go now we have access to our current user and now we have this upload task itself so right here with this on its own technically this is going to add files for us so if we come into here of course we're getting storage is not defined let's make sure we import storage from we need to go way back all the way to firebase and now hopefully that should go away we can upload a file let's just choose this random image and it's going to take a little bit of time to upload but if we come in here and refresh we should hopefully see that we now have a file inside of this files folder we have undefined so clearly this is incorrect we need this to say user id which is uid instead of just id but either way inside that folder we now have our bridge.jpg so if we just re-upload a file again let's just do this trees.jpeg now if we come into files we have that correct user folder id and trees.jpg and if i were to go into you know dsgf folder and i upload a file let's just do that bridge one now if i go back to the beginning into that user we have now our bridge and our trees.jpeg showing up this is not quite right though because we're in this folder dsg dsg whatever it is so it should be putting that inside of that folder but right now it's not so clearly something with our file path is incorrect just do a quick console.log of our current folder.path then also down here let's just do a log of our file path let's just see what this looks like so we come in here let's just upload our bridge and we're going to inspect down here go to our console you can see that our path right now has a length of zero and we have our bridge dot jpeg so the reason that this error is happening is because our current folder technically has no path so it's fall back into this but we're not actually including the current folder itself inside of our path our current folder should be included inside of this path here at some point so i'm going to rename this to parent path and what i want to do then is i want to create a separate variable called file path and this will be slightly different this is going to say if the current folder is equal to the root folder which we're going to have to import up here just like that so if it's equal to our root folder then what i want to do is just our file path is going to be equal to our parent pass we'll say parent path otherwise if it's not equal to the root folder then what i want to do is append my current folder's name onto my parent path so what i can just do here is say i want to get my parents a path i want to add in my current just like that make sure i spell current correctly now our file path here should hopefully be correct let's just try that again we're going to upload a file here we're going to upload this trees and now instead of here let's just go all the way back to the very beginning our files our user and now we have trees.jpeg and then our folder so clearly this is a little bit flip-flopped of how it should be and that's because our file name shouldn't be appended onto the end up here it should be appended down here and this should just be an empty string and then here our parent path should include at the end of it our file name so like that so in order to explain exactly what this is since it's a little bit confusing i kind of messed it up a little bit up here we're just getting the path for our folder which is our current folder path joined on these slashes and actually we can simplify this a step further by just replacing parent path with this we don't even need this at all so now what we've done is we take and determine if we're in the root folder if we're in the root folder ignore our current folder's name just take all the paths combine them with the slash and then add the file name to the end otherwise if we're not in the root folder still take the path also take the current folder's name and then append here the file name at the end now hopefully this should work first to test this i'm just going to kind of delete everything i'm going to delete all the files we currently have just to get a fresh clean slate i'm going to upload our bridge.jpg and i'm going to upload here our freeze.jpg so the tree should be in the root and the bridge should not so if i refresh this we go into our files into our current user and you can see trees is at the root and now we go into this folder and now we have bridges at this section so we're able to now properly put the files in the correct folder using this code and this code combined together but one problem is we don't have this information in our database it's only saved in our firebase storage we also need to save this in our firebase database what we can do is use upload task we can actually determine when we finished uploading so we can use this on state changed event and this is going to allow us to determine when things are changing as well as when our upload finishes or if there's any errors and this actually takes three separate functions the first function is going to be the function that gets called repeatedly telling us our progress of upload essentially our upload progress and for now we're just going to leave this blank we're not going to worry about it the next function is going to be what happens on error again we're going to ignore that for now the final function you pass to this is going to be the function that happens after the upload has finished itself completely what we want to do in here is take our upload task we want to get to the snapshot we want to get the actual thing that we're uploading we want to get the download url for it and this is a promise so this will return to us the url we can just say console.log url for now now if i come in here and i just upload a file we'll upload this randomtrees.jpg and i inspect go to the console you can see i get this url if i click on this it goes to the download for that exact file now i've got the download url i can actually use all the information i have to save this into the database so to do this let's just get database from firestore just like that and here instead of just doing a log we're going to say database.files.add and in here i want to add a file with our url i want to also take the name which is our file.name i want to set the created at i want this to be equal to essentially our current timestamp so database.getcurrenttimestamp then our folder id this is where we upload it to it's just going to be our current folder.id and then lastly i want the user that uploaded it so we're going to say current user.uid so now hopefully as soon as we finish our upload this should be saved into our database so let's do one final upload here we'll do our bridge.jpg and if we come back here we go all the way back to our cloud firestore inside of files we now have that file that we just uploaded as they created that date the name of bridge.jpg the url we can access it they use that uploaded it and the folder id is null because we're not in a folder we go into a folder and upload for example this bridge.jpg now you can see this should add itself here as soon as it finishes uploading might take a little bit might even need to refresh for it to show up still not showing up so let's see maybe if we have an error happening so let's just inspect go into our console i don't see anything being printed out into the console but most likely we have an error because this didn't actually populate anything in order to make sure it wasn't just a fluke let's just try one more time uploading we trees.jpeg this time and there we go it looks like maybe i just didn't do my upload properly so now if i click on this you can see our folder id is the idea of the folder that we're currently in which allows us to get essentially the child files as well as the child folders so before we continue on with this path of this add file button i want to go back to our use folder hook because now we can do a separate use effect to get our folders or our files i'm sorry now we can access the files that have a folder id equal to this folder id and the user id equal to our current user id and again we're going to order that by created at and we want to set our child files and here our thing is going to be child files and then way all the way up here at the top we need to create another action for our child files so child files is going to be setting our child files to our payloads.child files then up here we need search set filed files and that's just going to allow us to update the files themselves and the folders now we have an action for folders and files down here our action is essentially saying every single time that our folder id or our current user changes get the new files now here we should have our child files accessible and we can actually render them out to the screen inside of our dashboard component if we go to our dashboard we can do a very similar thing we did with our child folders but we can do it for our child files let's just copy this paste it down we wanted to do this for child files and here child files and we want to get that variable from here child files and you just say child file filed file dot id and we want to render a component called file also i wanted to see if we have child folders if it's greater than zero if i spell it correctly as well but we have folders and we have child files so if their length is also greater than zero then i just want to render out oops in a simple hr component it's just going to give us a nice separator between our folders and our files so if we have both folders and files on our screen it'll give us a line separating them that's only going to happen if we have child folders and child files now the next step is obviously going to be creating that file component and this is luckily a really simple component so we can say file.js rfc to generate that and this is going to take in a file all we need to do in here is render a simple anchor tag we want this anchor tag to have an href that points to our file url and the target is going to be underscore blank and the reason for that is we want to open in a brand new tab also we're going to have a class name here which is button we want to have it be button button outline dark and we want to have the text truncate and the wb-100 again just so if we have really long file names they'll disappear in here we want our file.name and of course we're going to use font awesome and that's because we want to have a file icon so we'll do fa icon i'm sorry fa file there we go close that off and give it a class of mr2 just to give it a little spacing from our text itself so now if we refresh this we're still getting that error because we need to import file in here so this should be file file and now you can see that if we go to something that has a file inside of it for example our root should have files inside of it they should be rendered inside of here but it's not being rendered so let's just make sure we inspect to see if we have any errors and of course it says error in snapshot listener the query requires an index you can create it here we need to create that index that's just because we're ordering by created at so let's just click create here and again that's going to take a little while to run so while that's running just to test to see if this works let's get rid of that order we're using on our child files and go back to here and we should hopefully have our files being rendered and of course cannot read property url of undefined and that is occurring inside of here we're saying our file.url is undefined so the file we're passing is not correct if we go to our dashboard let's make sure we're passing our file and of course this should say file instead of folder that should fix our problem and there you go it does so now we have access to our file we click it and it opens it in a new tab we go into this we now have a file here and we can open this in a new tab so we can access our files and our folders now really the final thing left is in our add file button we need to handle these different sections to be able to show people a progress bar in the bottom right determining how far the upload has progressed because if they upload a lot of files or a really large file we want to be able to show them that there's progress happening so what we can do is create a simple state so let's just import use state and in this state i want to track all the files that are currently being uploaded so we'll say uploading files set uploading files this is going to be equal to use state and by default this is just an empty array because we don't have any files being uploaded to begin with now what happens is when i start an upload i want to add a file to this so when i start an upload i'm going to set uploading files based on my previous uploading files i want to return an array here that has all of my previous files and i want to add in a brand new file which has an id that we're going to generate it's going to have a name which is the file.name it's going to have progress which is going to start at zero percent and an error which is going to be false because it's not erroring out so to generate this id we're going to use uuid for that so we can just say const id equals uu id v4 run that as a function and we need to make sure we npm i uuid in order to get this library imported and then up here you can say import v4 as uuid v4 we want to import that from uuid so this should give us that uuid library which just allows us to generate unique identifiers now if we save that hopefully this will add the file to this uploading files whenever we start the upload process to determine if this is working or not let's actually create a thing that renders out all the files we're uploading glue that down here let's wrap this in a fragment then down here we're going to render out all the files that are currently being uploaded so to do that first let's see if we have any files being uploaded uploading files.length is greater than zero then we need to run some code in this code i want to actually use react dom dot create portal we need to make sure we import react dom up here so import react dom from react dom just like that and essentially a portal allows us to create code that is going to be rendered somewhere else than inside the current component if you're unfamiliar with portals i have a video on them that i'm going to link up in the cards and description down below but essentially this portal we want to create an element inside of it and this element is a div you're going to have a bunch of custom styles these custom styles are going to be for positioning it absolutely so we say our position is absolute we have a bottom of one rem we want this to be in the bottom and we also want it to be on the right so we're going to use one rem on the right as well and we're going to set a max width of 250 pixels just so it doesn't take up the entirety of our screen and we can close off that div and inside of it is where all of our code is going to go for each one of our individual files that we're uploading we want to map through each one of our files and we want to render out some code and then finally way down here for our react dom create portal it takes a second property and the second property is where we want to render the portal in our use case i just want this portal to be on the document.body so we're just going to pass that in that's where our portal is going to get rendered out now for our uploading files we're going to use something called a toast message and we're going to be importing that from bootstrap so if we come up here just make sure that we import toast from react dash a bootstrap just like that also this up here should say react dom just like that because that's how we spelled it all the way down here now we have our toast and of course we need to have a key which is our file dot id inside of our toast we're going to have a header so we say toast.header and inside of this header all we need to do is put our file dot name and we're going to put a few little styles on here so we'll say class name equals text dash truncate w 100 and d block that's just so if our text is too long it'll truncate itself next we need our body of our toast inside of here we're going to use a progress bar from bootstrap so progress bar make sure we import that properly from react bootstrap just like that and down here inside of our progress bar we're going to have a quite a bit of code we want inside of here a progress bar to have a variant this variant is going to be determining if the file is errored or not so if it's an error then we want this to be danger otherwise we wanted to say primary so to be blue also animated is only going to be true if it's not an error so if we don't have an error i want the progress bar to be this nice cool animated look the now property determines where at in the progress bar we are between 0 and 100 so this is going to be set based on the error as well if we have an error then obviously we want the progress bar to be full 100 to show that we have an error otherwise we're going to get the progress that we have and multiply it by 100 because this is going to be a decimal between 0 1 multiply it by 100 will give us a value between 0 and 1. and finally we want the label of our progress bar if we have an error we want this label to say error make sure we capitalize it otherwise we want this to essentially be the current progress that we're at so to do that we just want to say math.round our file.progress times 100 and then we put the percent symbol at the end we're going to take our number between 000 we want to multiply it by 100 that's going to give us a percentage between 0 and 100. so we have between 0 1 multiplied by 100 we get a number between 0 1 we round it off so we get rid of all the extra decimals and throw the percent on the end so now that's pretty much all of the code we need to render out our individual uploading files so if we try to upload a file just come in here and upload a random file you can see our message pops up down here and our progress bar is at zero and that's because we're not uploading our progress bar at all also we have this close button we don't really want this close button unless the actual thing had an error so in our header let's just say close button is only accessible if our file was an error so now hopefully if we try to upload something like bridge we don't have that close button anymore only if we actually have an error in our file now if we go up here always remember when i said the snapshot runs all the time and tells us the progress of our upload well we can get that progress by taking our snapshot dot bytes transferred and dividing it by the total amount of bytes that it has to transfer so snapshot.total bytes this is how many bytes we have to transfer and this is how many we have transferred so far this will give us a percentage and then we can take our uploading files and we can set them to a new value and then here we just say return previous uploading files we want to map them so for each upload file i want to determine if the upload file dot id is equal to the id we generated way up here there it is so if we're on the current same id then i want to return essentially the exact same file but i want to update the progress to be based on the progress of this bar right here and then otherwise way down here i just want to return the upload file if it doesn't match the current id so now hopefully we should see the progress bar update itself when we upload a file so click on here and you can see the progress bar steadily increasing and the percentage inside of it and once it reaches 100 it shows up right here and once it reaches that 100 we obviously want to remove it so in here this is what happens when it reaches 100 we want to remove it so we can do the exact same thing set uploading files previous uploading files and what we want to do is just take oops take our previous uploading files we want to filter them and all we want to do is take it where our upload file is not equal to the current id so if the upload file dot id is not equal to the current id then save it otherwise remove it now we're of course getting an error that's just because we need to return here and now we can do is if we upload hopefully as soon as it reaches 100 it'll clear itself out so 100 boom it disappears in here is where we handle errors i just want to set our uploading files based on our previous uploading files and i want to return our previous uploading files dot map this is going to look very similar to the function above it so for our upload file if i spell that correctly if the upload file dot id is equal to our current id then return our object where we spread out our current upload file and i want to set error to true otherwise we can just return our upload file so if we have an error in the upload process it'll set this error here to true now in order to actually simulate an error what i want to do is just take our error code copy it down here and comment out this code for now so this is going to simulate what happens if there's an error so we can kind of test it as soon as our code reaches 100 it'll look as if it was errored out even though it technically succeeded so now this is what it looks like when we have an error because if we have this close button right now clicking it does nothing so we'll need to hook that up and also you can see it says error instead of the percentage and it still has the name and it has this red color so to make that close button work we need to come to our toast here we need to set up an on close handler and this on closed handle is going to be pretty straightforward it's going to be a function and in here we're going to set our uploading files we just want to remove our file so we're going to say previous uploading files return our previous uploading files dot filter we want to filter on a file that doesn't match the correct id so upload file.id is not equal to the file.id if it doesn't equal the current file then don't remove it otherwise remove it now what happens is if we simulate that error again by uploading bridge.jpg wait for it to finish loading up here and then this x button will allow us to clear that out so we can clear out any of those errors let's just come up here get this code back where it belongs and let's make sure that we just delete this because it's already up here now hopefully let's just upload again to make sure this is working upload bridge and it could go all the way to 100 and then boom it's right there you're going to notice something really interesting though we have like eight bridge files right here even though all these bridge files are exactly the same they have the exact same name they're in the exact same location they should be overwriting each other because if you add a file with the same name to the same folder it'll overwrite itself we want to build that functionality in so here instead of always adding a file we first want to check to see if it exists so we'll say database.files we want to get it where oops dot where the name is the same so if the name equals the and if the user id is the same as the current user.id which is uuid if that's the same and if the folder id is the same on the folder sorry current folder not id if all of these are the same and we're able to actually get something then we want to do an update instead of a create we're going to do a dot git which is asynchronous so we have dot then and this is going to give us our existing files and if we have an existing file which is just going to be the first element in our array so existing file equals existing files of the first one so if we have an existing file we're going to get that from the docs then what we want to do is update that so if existing then we want to take the existing file dot ref we want to update it and we want to update just the url so we're going to say url is equal to our new url we're updating the url to be the new url of the file we uploaded otherwise what i want to do is add it since we don't currently have one so we're going to take our add code and paste it into there but now if we upload a file with the exact same name it should hopefully update the existing file instead of adding a new one in order to make sure this is working we just need to delete a bunch of these files that we currently have added so i just want to come in here i'm just going to delete pretty much all the files that we have one by one so delete that one let's delete this one the reason i'm doing this is just so that we don't have any of those weird duplicates let's just delete all the files that we have inside of our database one by one here luckily we don't have too many to delete and the reason i'm not deleting the entire collection is because i already have the index set up on the collection and i don't want to regenerate that index because like i said it's pretty slow now we have all of those deleted and what i want to do just minimize this down a little bit we'll go over to our firebase storage and i want to delete all of our files in here so that way our database is as clean as possible everything is deleted and back to normal so now what we can do is go back into our cloud firestore we have no files at all which is great next thing that i want to do is just add one so i'll add one at the root here of bridge.jpg it's going to load up as soon as it finishes loading we should see it appear right here if we refresh over here we should see we have that file right here now what we can do is re-add that file a second time so add bridge.jpg again let's make sure i actually click on that properly bridge.jpg it looks like it's not doing anything so there must be an error let's inspect you can see using target blank that's fine that doesn't matter we're not actually getting an error let's see if we can still upload like trees.jpeg that's working just fine now let's go back try to re-upload that bridge one okay now it's working again so let's wait for that to go all the way through and you'll notice it doesn't actually create a new element in here it just updates the one that currently exists as you can see we only have two files here and we can just click on them and open them up just fine but now we're getting a permission denied and the reason for that is interest and if we inspect you're going to notice we're going to get an error for firebase insufficient permissions the reason for this is that if we go over to firebase and look at our rules we only have rules for reading and creating we don't actually have any update rules so it didn't update our file with the correct url we need to make sure we write in an update rule now this update rule is going to be really straightforward we're going to say allow update if we're authenticated so if we're off and we want to make sure that we match the user so we'll say matches user from the resource.data and then finally we want to have another check to make sure we're not updating the user id field we'll say user id because if we're updating the user id that's really really bad so what we can do here is say function not updating and we want to take in a field the first thing we want to do is we want to just see if this field is even passed up so if this field is not in not in the request.resource.data then that's fine we're not updating it next we need to check to see if the resource dot data of that field is equal to the request not resource dot data of that field so essentially we're saying did we even pass up the field that's what this first check does if we didn't pass the field that's fine it's not being updated if we did pass the field though then we're checking to see if the data from our current resource is the same as the field that we're passing up and again if so we didn't update it so now what we can do is go back in here we can upload like trees for example it's going to go through just fine and when we click this it actually updated our url which is why we're able to open it and bridge still is broken but if i update bridge again you can see that the progress bar is going to climb all the way up when i click bridge jpeg it now works and that right there is all it takes to create this google drive clone if you enjoyed this video make sure to check out my other project based videos linked over here and subscribe to the channel for more videos just like this thank you very much for watching and have a good day
Info
Channel: Web Dev Simplified
Views: 68,145
Rating: 4.9816513 out of 5
Keywords: webdevsimplified, google drive clone, react firebase, google drive firebase, firebase react, react js firebase, firebase tutorial, firebase js tutorial, react js tutorial, react hooks, react project, firebase project, firebase storage, firebase auth, firebase firestore, firebase database, firebase storage project, firebase storage tutorial, javsacript, js, firebase js, firebase javascript, firebase javascript tutorial, firebase, firebase google, firebase database react, react
Id: 6XTRElVAZ9Y
Channel Id: undefined
Length: 111min 40sec (6700 seconds)
Published: Tue Jan 26 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.