Now we're really close to the end of this module therefore, we need to make sure that we now dispatch
actions for creating a new product or for updating a product
and therefore first of all we need to add these actions here in our actions folder.
So I'll export a constant here, create product like this here, create product and then here also, another identifier
for updating in product with update product and update product like this and create fitting action
creators or create product and now it's up to you how you want to structure this, what data you expect
to get when you create a product.
I'm a fan of creating the product really here in the action or in the reducer,
so I actually expect to get a title here, a description, an imageUrl and a price let's say and then
I return an action object where the type is create product and the product data is simply all that data
merged together.
So here I have my title which is mapped to the title we get as an argument, description mapped to description
and therefore we can also use a modern Javascript shortcut where if the property name and the value variable
name is the same, you can just write it like this,
so if it's the same like price: price, we can just write this here, of course that's also possible
for title and description
so that we map all these arguments into properties of the same name in this object and if we update a
product that's relatively equal, update product, so we can generally copy that but there is one important
difference. Here we also need the ID of the product which needs to change, so we get this as an extra
argument and we can store this in our action therefore in a separate property of our action object. Now in
the reducer,
we of course need to handle that,
we need to handle the creation and updating. So let's add a new case here in the products reducer for
create product and for that, make sure you import create product from actions products and of course one
for updating a product with update product, make sure you import that as well.
In create product, of course we need to create a new product and I'll store it in a constant here with
the new keyword in the product model we created earlier,
for that you just need to make sure you import this product model here from the models folder and that
product here receives an ID which for now can generate manually with new date to string to have a
kind of pseudo unique dummy ID for the moment later, this will be generated on a server but we don't
have that yet.
Owner ID for now is hardcoded to U1 because we have no users in this app right now
but title and so on can be populated with data from the action because in the action for creating a product,
we have the product data key and that holds an object with title, description,
imageUrl and price and that's data
we can now retrieve.
So here for title, we get action productData.title, for the imageUrl, it's action.product
data.imageUrl, unsurprisingly for the description, it's action.productData.description
and for the price, it's action.productData.price. This is now a new product I create.
Now we need to add it to our store by returning our updated state here, where I first of all copy the
existing state and now I need to add it to both the available products and the user products because
we created it, it certainly therefore belongs to us, so it needs to be part of both arrays and the available
products, well there we can take these available products we got and use concat to get a new
array which is the old array plus add new element and here, new product is that new element and I do
the exact same thing here for user products.
So here I use state user products and I concat my new product. Now what about updating? For updating,
we first of all need to find the index of the current product,
so product index could be a constant name can be found by accessing our user products and there with
find index which is a built-in Javascript method, we can find the index of a certain element.
Again this takes a function which executes on every element in that array and that needs to return true
so that we have an index and there I will look at the IDs and look for the IDs where it's equal
to my pid, my action pid
because if you remember how we set up that action, for updating we do have the pid field here which
holds the product IDs we're getting.
So I'm looking for that product and then I store the index of that product in the user products array
in the product index here,
now we can create an updated product here which is technically a new product object but of course
prepopulated with some old data,
for example we keep the ID,
so we take action pid as a value here.
I also keep the owner ID and for that, I can access state user products for the index
we just find out, so for that product index, .ownerID, I won't change this.
Of course I will store the new title,
so here I will store action.productData.title, I will store the new imageUrl, so action.product
data.imageUrl and I will store a new
description, so action.productData.description. However I mentioned the price should not be editable,
so as a value for this, I will keep the original price, so state user products product index.price
here. By the way that also means that our action is not entirely correct, there
I also expect a price, I shouldn't do that because we can't enter it in our inputs anyways, we don't
need it so we shouldn't expect it here, we shouldn't forward it as part of product data for update product,
for a new product we need it but for updating, we don't.
So with that, we have our updated product with some new data and some old data, now we need to update
our state of course and for that, we have the updated user products where in the end I copy my existing
user products with this syntax here to create a copy and then I set updated user products for the selected
product index equal to the updated product, so I replace the product at this index with the new updated
product in my copy, not in the original array but in my copy. I need to do the same in the available
products but there I first of all need to find the index because that index here only works for the user
products, the index in the available products is very likely a different one,
so I have my available product index here if you want to call it like this, which generally has the
same selection logic, so we can copy that but of course I will look into the available products array
instead of the user products array. And now again, here we can have the updated available products where
I copy my state available products and then I set updated available products for the given product
index equal, excuse me for the available product index of course equal to the updated product,
so that I replace my existing product with the updated product in both the available products and the
user products array. Well and now, we just need to return our new state, first of all copy the existing
one and now set available products equal to updated available products and set user products equal
to updated user products, so to my updated arrays I'm configuring up there. With that, we hopefully have
all the logic we need, now let's dispatch these events from inside the added product screen. So here we
need to import use dispatch from React Redux and import our actions, so import everything as products
actions from the store folder, there from the actions folder and there from the products file and then
dispatch these things in the submit handler of course. Here, what we dispatch depends on whether we're
editing or adding
amd as I mentioned, we can find out what's the case with the help of edited product, if it's set, we're
editing, if it's not set, we're adding.
So in here, in the submit handler, we can add an if check and check if edited product, if that is set, we're
editing,
so then I want to dispatch my update product event, for that, first of all, I need to create that dispatch
function with the help of use dispatch and now with that created, down there we can call dispatch
products actions update product because that's what we're doing here
and now forward all the data we need here
which is my prod ID,
that's the ID of the product we're editing, we're extracting that up here
and of course in addition, also forward the title, forward the description, all these state constants
we have here, our imageUrl and not the price because we don't need that and in the else case here,
that means we're adding,
then I want to dispatch products action.create product, here
we forward title, description, imageUrl and also the price
and with that, we should have a setup where we hopefully can add and edit products.
So let's save this and
let's take a look. If we now go to the admin area here and I added this and I add an exclamation mark here
and also one here in the description and I hit save, I get undefined is not an object, evaluating props
price to fixed.
So looks like I lost my price here when trying to update this.
Well okay before we fix this, let's see if adding a new product works at all.
If I add a product here with test, test which is of course not a valid imageUrl, so we'll not see an
image but at least we sip at something, this is also a test.
If we try this and I hit submit, this also doesn't work,
so somehow saving the price doesn't work
and I think the problem is here of course, the problem here is that price is actually a string here but
should be a number, so we can easily convert it to a number by adding a plus here before we pass it to
create product, for updating on the other hand, if we have a look at our products reducer, it should normally
keep the price it already had.
So let's see if that plus fixes it for adding or if there is a different issue as well,
this was a change that's required anyways but let's see if there is another problem. So
test, test, twelve please enter only numbers here, not some text which you currently could but which would
break it, test this, press this button, yes that doesn't look too bad,
we got some problem with the image here but if we scroll down, actually here if we dismiss this, we can
see here's our product,
so price is missing, so something's wrong there
and we also don't seem to save the image correctly,
not only because it's not displayed but because of that warning we got
but generally, this works.
However for example here if I try to update and save this, we still get an error, so there's still
something wrong.
So one thing that's wrong is in the actions of course, for update product here, the type should be update
product and not create product,
otherwise we trigger the wrong action in the reducer which explains the price error we got there.
So this has to be update product here for updating a product unsurprisingly.
So that's one problem but another big problem can be found in the added product screen. I use my use
callback method here to wrap the submit handler right and I do this to avoid
unnecessary recreations of the functions.
The problem is I initially set this to have an empty array as a dependency list which means this never
is recreated which made sense when we only had console log in there
but now we're doing stuff in there and now we actually do have dependencies.
Right now I never recreate this function which means it never is recreated for its updated values.
So when we submit our form, we never take into account what the user entered.
So actually now we need to specify dependencies here,
the dispatch function but more importantly even, the prod ID, the title, the description and the imageUrl
and also of course the price. Now with that if we save this, we should be fine and all the
issues should be gone.
So let's wait for this to reload,
go to admin now and start editing this maybe and now if we add an exclamation mark in the title and in
the description and we save this and go back, we see that here and if we go to products, we also see it here
and in the details, we also see that exclamation mark.
Now if we go back to admin and create a new product,
test, test,
twelve, test this and I save this and I go back,
now this also shows up down there. Of course the image doesn't show up because we haven't entered a valid
URL but all the other data shows up, so this is generally working
and of course you could enter a valid imageUrl and that would also break, let's quickly test
this as well. So let's go back to the admin section and add a shelf here maybe, for that I selected the URL
of a shelf I found on the internet for 199.99, this is a nice
shelf like this. If we now save this and we go back, this looks good, here's our image and we also
see that here on the product screen and we can view it here as well.
So this seems to work
and with that, we generally have a set up that does work.
Now there are minor things which I want to work on, for example before we delete, it would be nice to have
a little confirmation dialog and in addition, I want to make sure that when we added or edited a product,
when we click save here, we automatically navigate back.
So these are just minor things of course but I think they make for a nice final here in this module.