‫Now it's time to also edit a cabin.
‫And so for that we are going to reuse the form
‫that we have been building.
‫So this is gonna be quite an advanced lecture here,
‫but we can do it.
‫So let's get started.
‫And, first of all, let's add an edit button here
‫to each of these rows.
‫Maybe let's actually delete some of them here as well.
‫So we don't need all of these here.
‫Maybe we keep three.
‫And so now in each cabin row,
‫again, here let's actually add a div
‫so that we can then add another button in there.
‫Yeah, so just like this.
‫And so here what we are going to do
‫is to again temporarily create a state variable,
‫which, if true, will display the form
‫right here below this row.
‫So later on we will have this in a modal window,
‫but, for now, let's just do it like this.
‫So showForm and setShowForm,
‫useState, false.
‫So what this button will do
‫is to only toggle that state variable.
‫And so if that state variable is true,
‫we want to basically display that form
‫outside of this table row.
‫So basically right here.
‫So if showForm,
‫and here we want to import that.
‫Now here the autocompletion is not working
‫because we will need to be inside this fragment,
‫because otherwise we end up with two parent components.
‫And so here we will then import
‫and display CreatCabinForm.
‫So let's try this.
‫Close this one.
‫And nice, so this looks decent,
‫at least good enough for us to work with it for now.
‫Now, okay, so now here we will need to,
‫of course, pre-fill all these values
‫with the data from the current cabin.
‫So what this means is that we need to pass
‫that data now into CreateCabinForm.
‫So let's here add a new prop called cabinToEdit,
‫or for editing or something like that.
‫But I like cabinToEdit, it's a bit shorter.
‫And so let's pass that in,
‫and then, in our form, we will need to accept that.
‫So here in the form
‫we are now going to make a lot of changes.
‫So let's actually first duplicate this file,
‫but maybe let's first also clean it up a bit.
‫So all the stuff here we no longer need,
‫and neither do we need this,
‫and let's also reorganize our inputs.
‫So these external libraries should always be at the top.
‫Then I like to have my components afterwards,
‫and then some other stuff.
‫Now, okay, so I just copied that.
‫Let's call it version one,
‫and now we will keep working on this one.
‫So let's accept then cabinToEdit
‫as a prop, and now here,
‫let's get some values out of this object.
‫So I want to grab the id,
‫let's actually, to make this all as clear as possible,
‫rename this id.
‫So this will be the editId.
‫And then, let's just grab
‫all other values into editValue.
‫And we are going to grab all this data from cabinToEdit.
‫Now, sometimes this value will actually not exist
‫and so let's by default make this here just an empty object.
‫Alright, and now how do we get these values into the input?
‫Well, thankfully for us,
‫there is once again a very easy way to do it
‫with React Hook Form.
‫So here we can actually pass in some options.
‫And so one of those options is the defaultValues.
‫However, if we are just using this form
‫to create a new cabin,
‫then we will not want any default values.
‫And therefore, first of all,
‫let's actually figure out if we are using this form to edit
‫or to add a new cabin.
‫So let's create a variable here
‫which will contain that information.
‫So let's call it isEditSession.
‫And then, let's simply convert
‫the editId to a Boolean.
‫So basically if there is an editId,
‫then this will become true.
‫And if it's not, then the Boolean will convert it to false.
‫And so here we can just use that.
‫So isEditSession, and if so,
‫then we want the editValues
‫to become the default values.
‫And if not, then just an empty object.
‫So let's actually try that.
‫And nice.
‫So that's looking great already.
‫Let's just now also adapt some things here,
‫for example, this text.
‫And so for that we are again
‫going to use that Boolean.
‫So here is editing session,
‫and if so, then let's return edit cabin.
‫And if not, then here let's say,
‫well, actually maybe create new cabin.
‫And finally here, let's think about the file upload.
‫So even with the default values
‫this file upload will still be empty,
‫so that image will, of course, not be placed here,
‫that's just not possible.
‫And so usually when we edit this data here
‫we simply want the image to stay the same.
‫So, in this case, we want to be able
‫to submit this form here
‫without actually having this photo.
‫And so this should then not be required in this case.
‫So let's again ask if is editing session,
‫then here we can return false,
‫and otherwise we return this string
‫which will then make it so that the field is required.
‫All right, so the form is now basically working.
‫And so let's come here again to create the function
‫to edit the cabin.
‫Now actually what I want to do
‫is to also reuse this function,
‫because otherwise we will basically
‫be duplicating this entire code
‫except for this one here,
‫because all the rest will stay the same.
‫So we will also upload new images if there is some.
‫And yeah, so everything here
‫will be necessary, like all of this.
‫And, therefore, let's just reuse this function here as well.
‫Now before we go do that,
‫I actually wanted to mention something earlier,
‫which is that by default,
‫this insert function right here
‫when we create a new row in the table
‫will not immediately return that row.
‫All right, so many times we actually do need that
‫and we do return the data actually from this function.
‫But right now that data will be empty.
‫And so if we want to actually return
‫that newly created object,
‫here we need to attach .select,
‫and then we can also attach .single
‫which will then basically take that new element
‫out of the array that it will be in.
‫But, anyway, now let's actually then reuse
‫this function here.
‫And, first of all, let's then rename it.
‫So createEdit function
‫just to let us know
‫that this function actually works for both.
‫And so then here we need to also change that.
‫So createEdit here, and createEdit
‫right here.
‫Now, if we want to edit a cabin,
‫then we need to pass in the new cabin data
‫plus the ID of the cabin that is being edited.
‫And so that's how we will know
‫if we are in an edit session or not.
‫So we want to create the cabin here only if there is no id.
‫So if there is no id,
‫then basically what's gonna happen is this right here.
‫Now here we cannot declare a new variable in here,
‫but that's no problem at all,
‫because we actually want to reuse this part here anyway.
‫And so let's now write this query here in a different way.
‫So let's declare a variable that we will keep adding to.
‫And so this simply starts
‫with supabase.from{'cabins'}
‫just like this.
‫And then, we can remove this part here,
‫and basically we then attach this here to the query,
‫so to this part that we created right there.
‫And so then, later what we can do
‫is to simply await that query that we created.
‫So this is exactly the same thing,
‫and it's a commonly used technique
‫when we want to reuse parts of the query.
‫And actually let's also remove this part,
‫place that here.
‫And so now let's say that this here is for create.
‫And then, let's have another one,
‫B for edit.
‫So this one is if there actually is an id.
‫And now let's then again get a code
‫for that right here from our API.
‫So in the API docs,
‫and, of course, I could just write a code,
‫but I want to empower you to work with this on your own.
‫So I'm showing you really where everything is coming from.
‫So inserting and updating works like this.
‫So this part we already have supabase.from.
‫And then, what we want is this update right here.
‫So only we are interested now in this part.
‫So query, and then we can just add this.
‫And before we change this,
‫let's actually not forget that we need
‫to also add a role level security policy for that.
‫Ah, we actually did that already.
‫Yeah, I remember.
‫So we did that, great.
‫So that saves us a bit of work now.
‫And so let's come back here.
‫So here we have the update operation,
‫and then, we again, just like with delete,
‫we have this equal operation, which means that,
‫of course, we don't want to update everything,
‫but only the row where the field of id
‫is equal to the id that we passed in.
‫And what we want to update is similar to this right here.
‫So basically the updated data, and then the image path.
‫Just notice that here we are not placing
‫that in an array like we had to do here.
‫So that's a small, slight difference right there.
‫Now, all right, now we might think
‫that with this we are finished, but we are actually not.
‫Because remember how we made this cabin photo upload here
‫optional for the editing session.
‫This means that sometimes when we edit the cabin
‫we will get a new file,
‫so if we select one here,
‫but if not, we will just get a URL from before.
‫So let me demonstrate that here.
‫So right here let's again
‫just lock the data to the console,
‫so instead of creating a new cabin.
‫And so now as I click Edit Cabin,
‫what we get here is the image path
‫that we specified earlier.
‫So just this URL here.
‫But if we do specify a file, let's say this one,
‫then we get this image.
‫So just like before,
‫then we get a file list with this image.
‫So we have these two different situations
‫that we need to account for.
‫So both in the form itself,
‫but also right here in this function.
‫And the way we're going to do this
‫is to create another variable
‫to check what kind of image this is.
‫So we're gonna say hasImagePath.
‫And so then we will check
‫if the newCabin.image.startsWith
‫the supabase URL.
‫So that's the trick that I came up with.
‫So basically checking whether that image right here
‫basically contains that supabase URL that we saw earlier.
‫So if we edit another one,
‫then as, well, let's place that.
‫So as I showed you earlier, then it starts,
‫well, not this one.
‫But this one here will now start the image
‫with the supabase URL.
‫And so, in this case, there already exists an image path
‫that we want to then keep in the database.
‫So then we don't want to create a new one
‫but just use that one.
‫So here in the image path definition let's say,
‫hasImagePath, and if so, let's just use that.
‫So that's coming from newCabin.image.
‫And if not, then, of course, we need to create a new one,
‫so based on that image.
‫Now here, this .image might not be a string.
‫And so, in that case, we cannot call this function.
‫And so let's do this optional chaining here
‫and let's do it also for the function call itself.
‫So we can do it like this as well.
‫But this we should be covered
‫and the function should work now.
‫And I know that it is quite confusing and,
‫well, as I said in the beginning.
‫But real-world development
‫is, of course, not always super linear
‫and this is just how it works.
‫But anyway, now let's use the function here, as well,
‫to again create a mutation.
‫So this is gonna be very similar to this,
‫so I will just grab this.
‫So copy/pasting it, but now here,
‫let's call this isEditing, like this.
‫And now let's also actually rename these mutate functions.
‫So this first one, let's call it createCabin,
‫and then here editCabin.
‫And here the success message will be
‫cabin successfully edited.
‫And then, here we actually also need to change something
‫in the mutation function.
‫So here in React Query,
‫we can actually only pass one element to this function.
‫So I'm not sure why that is,
‫but so let's actually create an arrow function here.
‫And so this will then, as we said,
‫only accept exactly one argument
‫which will be this object with the newCabinData,
‫so let's call it that.
‫And then, also the id.
‫And so then we immediately destructure that here
‫and pass it in the function as necessary.
‫So newCabinData and id, like this.
‫All right.
‫Now here we are not using DS editing.
‫So instead of just doing things whenever we are creating,
‫let's now do a variable that combines both.
‫So isWorking is then isCreating
‫or isEditing.
‫And so let's then replace the isCreating
‫in all of these different instances here
‫with this one.
‫Okay.
‫Let's get rid of this console.log.
‫And so here this one was for createCabin.
‫And now, of course, here we also need to handle
‫the situation of editing a cabin.
‫So let's again use that Boolean.
‫If is editing session, then what we will want to do
‫is to edit the cabin
‫and else we want to create a cabin.
‫And before we can do any of this,
‫now it's time to again account for the fact that the image
‫can either be this string right here
‫or it can be this object that we saw earlier.
‫So this image file list right there.
‫So this array basically.
‫So let's check for that
‫so that we can actually determine what image
‫we need to pass into editCabin.
‫So here we can use the type of operator
‫to check whether data.image
‫is a string.
‫And so if it is a string,
‫then the image will just become data.image.
‫And otherwise, so if it is that file list,
‫then we will again need the data
‫to be data.image at position zero.
‫So exactly what we have here.
‫And so then we can replace this,
‫and then we will also be able to pass that in here.
‫So remember that here we needed this object
‫with newCabinData and id.
‫So the newCabinData will be an object similar
‫to the one that we have below.
‫So that's the submitted data from the form plus the image,
‫and then the id is the editId.
‫And with this, we should be good to go.
‫Now I'm sure there is gonna be some bug somewhere here.
‫And so let's try this out in order to find that bug.
‫So let's edit maybe this first cabin right here.
‫And so notice that this one does have an image.
‫So let's change this here a bit.
‫88 guests.
‫And yeah, this would be enough.
‫So let's edit.
‫And, well,
‫it seems that nothing really happened.
‫Let's maybe reload here.
‫Maybe it didn't just revalidate the data.
‫Ah, but actually nothing did happen.
‫So we have surely some problem here.
‫So, first of all, let's check
‫if we are actually receiving our data in this function,
‫so the newCabin and the id.
‫So let's just change it to something.
‫And it seems like we are getting the data,
‫so that's already a good sign.
‫So we have the id and we have that new name
‫that we specified.
‫Yeah, but then something here didn't work.
‫So let's check.
‫And the problem actually lies right here.
‫So here we cannot do just this,
‫but instead we need to reassign the query variable.
‫So it needs to be query
‫then equals the query that we already have.
‫And then, we add here this insert
‫and here this update to it.
‫So I just forgot to place that there,
‫and so hopefully that will already solve it.
‫So let's try to edit this one again,
‫change this to 22.
‫And let's see.
‫So this is taking some time.
‫Ah, and beautiful, so now we got test.
‫Somehow we got 18,
‫even though I think we did 22 there,
‫so that's strange.
‫And also the image is gone.
‫So let's check that here.
‫So maybe for some reason we overwrote that URL there.
‫And, so yeah, this is always a lot of work.
‫There are always a lot of bugs,
‫because there are so many moving parts.
‫So here now we have a problem that this is called undefined.
‫So this means that something went wrong here
‫with this hasImagePath.
‫So let's again check our console.log,
‫ah, which is now gone.
‫So let's try to edit this one as well.
‫So let's call this one jonas.
‫Let's give it a capacity of 88.
‫So hopefully that will then work.
‫And so now this will probably break this image, as well,
‫but I just want to see what happens.
‫So here indeed, we have that image
‫which starts with the supabase URL.
‫And yeah, so now that image is broken as well.
‫Which means that here we did create a new image path,
‫and so that means that this here is not working.
‫And, ah, I see, it should be supabaseURL.
‫So what a stupid bug right there.
‫And now apparently we cannot delete,
‫but let's deal with that later.
‫We just try that again.
‫All right, but we will deal with that later,
‫but now we need to add more cabins,
‫because we need them to have
‫the correct image.
‫So let's use this one here,
‫and hopefully this still works.
‫And yeah, there it is.
‫Let's just create the 008 again.
‫And so then, hopefully,
‫we will be able to edit them correctly.
‫So let's wait for that to upload.
‫And there we are.
‫So then let's edit this last one here to test.
‫Now, and I see that sometimes when you scroll here,
‫then that changes the number.
‫So that's the reason why earlier
‫this must have changed from 18 to 22.
‫So let's make it, well, maybe just 100.
‫And so now we are not editing the image,
‫and so then we expect that this is not going to break.
‫So let's wait.
‫And yeah, nice.
‫So this part at least works now.
‫And even though the form
‫is not resetting for some reason,
‫even though it should.
‫So somewhere here we have that where we reset the form,
‫but for some reason that's not doing its job.
‫But I guess the reason is that it will then simply
‫automatically fill again the form
‫whenever the new data arrives.
‫So it will do the job temporarily,
‫but then it gets filled again.
‫All right, and now let's try this other one.
‫So here, or maybe here,
‫let's now upload the correct file again.
‫And so that should then overwrite
‫that image that is already there,
‫so that image URL, which right now is pointing to nowhere.
‫So now that's taking some time to upload here.
‫And beautiful.
‫So cabin number two now has the image again.
‫And now let's just test this one more time.
‫So I just want to be sure that this part is now working.
‫So here, let's try cabin number five maybe.
‫So let's edit, wait for it.
‫And, well, now I'm not even sure which one it was,
‫but apparently it did work, great.
‫So this was a lot of work,
‫probably a lot of confusion as well.
‫But, as I mentioned earlier,
‫this is just what web development is.
‫So things are not that linear
‫and you sometimes run into bugs,
‫and yeah, that's why I'm not going to cut
‫all of this stuff out of the video,
‫but instead show you the process
‫in which we can fix all this stuff.
‫Now let's try to delete this one here
‫that says jonas from here,
‫like just doing it manually.
‫And then, I will need to find out why there is a problem
‫whenever we try to delete it now like this.
‫Well, now it did actually work.
‫Well, that's super strange.
‫Let's try to delete this one as well.
‫And great, so actually everything now works,
‫including deleting again and also editing a cabin.
‫So we can edit it basically in two ways
‫which is to edit the image or to not edit it.
‫So that was, I think the most confusing part
‫here of this video,
‫and so please make sure to review everything
‫that we did here.
‫Of course, we could also have created
‫different functions here and different components,
‫but I think that might have been even more confusing,
‫especially if then at a later point
‫we had to change something.
‫And so I think that this is overall the best solution
‫that we could come up with.
‫But anyway, let's now finally wrap up this super long video.
‫And then, in the next one,
‫we will basically export these mutations and all the places
‫where we use React Query into our own custom hooks.