Okay, so let's take a look at what we have here and see how we can make this more reusable, not just
for our text field, but for things like our description field as well where we have multiple rows.
Our text field does take a multi-line property, so we can very easily convert this into a text area
type of input.
And we'll take a look at how we can achieve that.
So inside the app folder where we've got our shared folder and components, let's create another component
inside here I'll say new file and call it app text inputs X.
And then inside here we'll create the boilerplate we need as per normal.
And inside here we can use another react hook so that we can get hold of the controller properties.
So inside here we'll say const and then equals use controller Which is the hook version of what we're
using inside our component.
And we need to pass this some properties.
And if we hover over this it's expecting an argument and it needs some props.
So we'll create some props for this.
And up here I'll specify type props equals.
And we can get our props mostly from the text field props and the use controller props.
But inside here I'll specify a label and give it a type of string.
And then below or after the curly bracket.
Here I can use ampersand, and then we can use the use controller props we get from react hook form,
and we can use the text field props we get from Mui material.
So when we want to use our app text input, we get all of the props that we typically have with a text
field and then we can pass in.
And I won't destructure anything from this because it will be too big.
I'll just use props and props.
And then for our use controller we can, in curly brackets use the spread operator and pass in the props.
And that's the argument that our use controller needs.
And then we can destructure from use controller we can get hold of the field states and the field,
and then we can return inside.
Here we can use a text field, make it self-closing, and we can use the spread operator again to pass
in all of the props.
And then we can use curly brackets, spread operator again and use all of the field props inside here
the multi-line property will get from props dot multi-line.
And like I say, we've got all of the text field properties available inside here too.
We'll do the same for Rose, just in case.
We want to use this as a text area and specify props and rows.
And also we'll specify the type in here so that we can use it as a text input or a number input or one
of the other types of inputs of course.
So I'll specify props dot type for this.
We'll make it full width.
We'll give it a variant of outlines.
And we can also specify our error properties here as well.
So I'll specify error equals and then in curly brackets double exclamation mark.
And then we'll check the failed states and see if it has an error.
And then we can also use the helper text and set this equal to failed states dot error dot message.
So that's our reusable text input.
Pretty straightforward.
But It is straightforward.
And if we were not using TypeScript, that would be the end of our job here.
But let's see how we get on inside our product form when we try and make use of this.
So instead of the controller, etc. going on here, we can use our app text inputs we've just created.
I'll give it a self-closing tag.
We need to pass this.
The control that we've brought in from our react hook form up here.
So we pass each input the control and we need to give it a name.
And this is going to be name of name.
And I'll give it a label equal to the product name.
And we've got a warning here.
And if we hover over this then this is going to look pretty nasty.
And the reason is that it's expecting a control with the type of field values.
But our control that we're Her passing has a type of control.
And then this is our product schema.
Effectively our create product schema.
So it's not matching what the controller is expecting.
So we could cheat and we could say well this is going to get complicated very quickly.
And we could just remove our product schema from here as the type.
And then our control would be happy.
But then we start playing whack a mole with other elements in our page, because now our onsubmit is
not happy.
So we'd have to change that to something else as well.
And we could just use field values and take away the type benefits we do get with Zod and the schema
that we created and that works.
And that would work for our input here, but it does feel a little bit like cheating.
But let's just make sure that this is working as we stand at the moment, and then we can come back
and fiddle with the types.
So let's go back to our application.
I'll just refresh this because we're going to get some console warnings as we've been changing the code.
I'll click on create and we can see we've got our text input provided with the product name.
If I click in, in fact, we don't have validation at the moment because I've disabled that temporarily.
But we should be able to start typing in here.
And I've got an issue here.
Once again, it's going to be that uncontrolled input to be controlled.
So we need to give our text field or our controlled input effectively a default value as well.
So let's go back to the app text input.
And just after the props we'll add a default value.
And we'll set it to be just an empty string which should remove that warning we get in the console.
And I'll click on create again type in test.
Click submit and we get our output into the console there.
So the input is working.
But do we want to use the cheats approach or do we want to provide our schema type that we created.
I'm going to say that we're not going to cheat, but this is slightly tricky to accomplish.
So I'll put things back to how they were with the create product schema, and where we've got the control
that now has the warning.
And to resolve this warning, that does involve some trickier aspects of TypeScript that we'll need
to take a look at.
So let's head over to our app text inputs.
Now we need to get field values to this.
We can't use our create product schema because we would like to use this input in other locations as
well.
And we need to give this some type information so that we can use our control in this way.
So we need to use generic types which means giving it a type.
In this case for our props, I'm going to specify T and say that this extends the field values.
That's what we used in our form just now.
And we know field values works with our control.
Now what we also know if we go back to our product form and we hover over the control, then each one
of our inputs is going to have a property unique to that particular control.
So we also need to get that information into our type info as well.
And we can do that by specifying the name property in here and saying it has a key of T.
And that will give us type safety for the name of the inputs that we're using with our text input,
based on the schema that we created for the create product schema.
So back in our text input bit, more work to do with our types.
Our use controller props will give this the type of T as well.
And when we use a generic type in this way, then at compile time this gets replaced with what we're
actually using when we use this text input in our product form.
So it's going to know that for our text input, we're using a type of create product schema that extends
the field values.
So we've got our use controller props of type T.
Then we need to give our app text inputs a type property as well.
And we'll specify t.
And once again we'll say extends field values.
And then we can give our props the type of T as well.
So as with anything in TypeScript we fix one thing.
Because now if we go back to our product form we've fixed the control.
Yay!
But we've broken our text input.
So whack a mole so we can't use default value here.
We'll take that out and instead we'll specify the value inside the text field itself.
Now control inputs instead of using default value we use value inside here.
But we have to define the value which is going to come from the fields dot value.
Or it's just going to be an empty string.
And now let's go back and clean up our product form.
There's way too many errors here, but we've got things that we're not using that we've imported.
I've got something commented out here.
Let's uncomment that.
And I'm going to remove the mode of untouched because that's giving us an issue with testing our validation
because we've only got one input field.
And I'll also remove the unused imports from in here as well at the same time.
And great, now everything is clean.
But does it work as we'd expect it to?
So if we go and take a look and let's just refresh this page and I'll click create.
And if I type in a product name I'll say test and click submit.
I'm not going to be able to submit because of the validation.
But if I do take out the product name and then I click submit.
Still nothing that caught me by surprise.
Let's go back to our product form and see what's going on here.
Okay.
let's take out the validation temporarily.
Make sure that we can submit without validation being involved.
So I'll just refresh this page again and I'll click create.
And just type in test and click submit.
And we see the output inside here.
But I was hoping to see validation errors as well.
And let's put the schema back in again.
The Zod resolver back in.
If we don't use the mode of on touch, then in theory what should happen when I click submit is I should
at least see the validation error for the single inputs that we have here.
So I'm just going to refresh that page again and I'll click create and I'll submit.
And there we go.
We do see the validation.
And if I start typing the validation error should go away.
Obviously with just a single input.
This is hard to demonstrate our validation working when we've created all of the validation in our schema.
So we need more inputs effectively.
And in the next lesson we'll start to look at addressing just that.