YTread Logo
YTread Logo

Building a Google Forms Clone with React Native: Form Validation with Zod

May 07, 2024
so we are live, what's up, not just developers, welcome back to a new tutorial, today is Friday and today we are going to create a

clone

of Google

form

s. Well, we all know that Google Forms now has this reputation of closing projects with the last one. Being Google domains and before they decide to close Google Forms, let's go ahead and learn how we can create Google Forms mobile apps ourselves using

react

native

. At the center of this tutorial we will actually learn a much broader topic when it comes to managing complex multi-step

form

s in

react

native

, these types of use cases are present in almost any application you are

building

and without the right tools you will It becomes really difficult to manage these multi-step forms in this tutorial, however, I will show you.
building a google forms clone with react native form validation with zod
We present a pretty fun way to manage these complex forms by using various technologies and then we will have a forms management system that will be very simple and will We will manage with the following tools for this project. We are going to use react native role for the UI elements for the forms such as text inputs, radio buttons, checkboxes, etc., then we will manage the form logic and

validation

using form binding. reaction and powered by Zod. We're going to validate all the fields that we have in our form using um, yeah, this powerful typescript validator called Zod.
building a google forms clone with react native form validation with zod

More Interesting Facts About,

building a google forms clone with react native form validation with zod...

We'll do this by simply defining the schema, basically what our data should look like and then Zod will validate it and we'll send it. the mangled hook bugs and we'll see them on display using native reaction paper. It will all be done in the context of a post react native app. For this specific, we will use the export router to manage the navigation between screens and also typed text, so in the end what we will have is a real example of a verification form where we have several steps, in the first one we are going to collect personal information and then maybe the delivery information and lastly payment information, so let's put all of this together in an app that looks like Google Forms but is much more useful for mobile apps.
building a google forms clone with react native form validation with zod
This tutorial will be useful not only for payment forms, but you can also learn a lot. from here and apply the same knowledge, the same system, to other use cases where you have these multi-step forms, like user and service registration feedback, a reservation form where you can book some accommodation or something else , a job application or even onboarding, so there's the plan for today if you're ready, bring us a cup of coffee and let's jump into this foreign, who's watching this life, how's it going guys? Are you excited for today? um and I think for everyone else as you say hello and leave I know where you're joining us from today as I learn I'm going to start because we have a lot of things to do today to create this application so let's go ahead and start by initializing an empty project using the reaction hook form. no rack hook form using Expo and it also reacts to Expo router so first of all let me go to my project and when you are in the folder where you save your projects let's go ahead and run npx create Expo up let's make sure to set it to more take to To grab the latest version of the createx post, let's provide the name of our Google Forms application and provide a template that we will use to get started and we will use the router.
building a google forms clone with react native form validation with zod
This will start from a template you already have. router with router oh is it um with Dash router like this? This template will come pre-installed with the router and configured so we can start cleaning up and have this navigation system already installed. Hello Daniel from Amsterdam, how are you, Amadeo? Hello, hello, so, yes, let's look at our installed application while we wait for npm to install our dependencies. This is a great time to pause the video, minimize it and hit the like button and also make sure to subscribe to the channel because according to our stats, I mention that, not this one, where is it?
I always miss it oh here it is according to our analytics we see that only one percent of you watching this video are subscribed to the channel which is a little crazy so guys please if you don't . Don't mind, hit the Subscribe button and let's continue with our tutorial. This is our Elite group of the one percent of people in the Club who are subscribed to the channel. Let's go and as you can see, doing that actually worked on our project is ready, let's move on. and open it in Visual Studio code um not like that but code and there we have the Google forums here we have it.
I can close that terminal and let's go ahead and zoom in a little bit for everyone to see here we have it come on oh there's a little problem open projects YouTube Google forums and Google forms let's open up oh boy. I dragged and dropped the icon over the folders here and now I don't know how to open it, but we'll get there. What we can do now is execute. our app, oh, it's actually here, folders, so I'm going to drag it over. Everything is back to normal, so now here is our empty Expo project with the export router.
Let's go ahead and npm start with the development server and run it right away. in the emulator, if you have emulators installed, go ahead and press I to run it on iOS or to run it on Android or if you don't have them installed, that's not a problem, the easiest way to run this app is to download Expo go. app from Apple Market or Play Store and then just scan the views QR code and you will have the app running on your physical device so you don't have to mess with Android Studio xcode etc. so let's wait for it to play. load and render here I need some air, coffee time, yes, we are doing well, now we have the application running and what we see is a splash screen that we get from the Expo router, in fact, we see this screen because we don't have it yet no screen in our application and by simply pressing this button on our device we will see that it automatically creates this directory in our project on the Expo router, this is where all our screens will be defined and by simply creating files in this application directory, we will create a separate screen in our application, so initially we have an index.js application and this is the splash screen and a little later we will add more screens for our multi-step form that I want.
What I want to do is work with typescript and as I see the file is index.js, let's go ahead and just transform from JS to TSX and if you stop the server and run it again, Expo will automatically see that we are. we want to use typescript in our app and we'll ask if we want to install typescript and the dependencies so let's press yes and this will go ahead and install typescript in our package.json and we can use typescript in our app can I use Expo on my phone? Yes, you can run Expo applications that you are developing using Expo go, by downloading it from the stores.
It is available for both Android and iOS, so now we can press I to run it again on the iOS device. maybe R to reload and here we see our application running with typescript, all good, perfect, so what's next? Let me go ahead and confirm everything before moving on to the next step. This is the first commit of the initialization. Okay, so we move forward as we are. To manage our multi-step form, we are going to create a separate stack navigator for it, a separate group of screens that will be managed as a single group, for that let's go ahead and create a new folder inside our application called checkout in checkout What we have to do here is first of all provide the home screen of our checkout basically the first route of the checkout that first route will be called index TSX and here we simply export by default the first route of our multi-step, if we look at our forms here the first route will be responsible for the profile for personal data like name, email etc. so let's call this function.
This component, personal data, is going to be a function that just returns Right now let's just return maybe a view and some text that says personal details. We need to make sure that we import the view and the text from react native and the text also from here and how we can see this page well in a moment. how we can navigate from one page to another using links, but the way the export router works is that it works based on URL very similar to how we browse the web, so it will be easier to display this navigation system in a Web navigator. and let's go ahead in our dev tools and press W to open it on the web, so if I'm going to open it on the web, it actually opened it here and now, basically, the way we navigate here, what page we navigate to here, it's will assign. it's going to map to the screen that we define in our app, because we don't have anything that basically means this is the home screen, the root screen and this screen is our index.js with hello world, but if I'm going to make a slash checkout , we will see that here we see personal details, which means that if you automatically created this path, every time we go to a payment with slash that comes from our name folder, it will show the home screen of a payment with personal details.
Likewise, maybe you can make a font size of style 30 so we can see it better. Yeah, maybe I can do it like that for a moment. Now let's go ahead and define the screens for the other steps we're going to have. the second step will be to deliver information, so let's copy and paste this index from the payment folder and instead of copying the index, let's call it delivery, yes, Lee, and this delivery let's call the delivery details of the component and here delivery let's do the same one more time. deal with the delivery and rename the last step is payment payment information payment so the component will be payment details and here also payment Now when we go to the checkout, we see the personal details because that is our index.tsx if we are going to checkout, then slash our file name, for example, delivery, slash, delivery, then we will see the screen with the delivery details and if we go to checkout, we will see the payment details, so now with this set of files, all the tabs on our form will be handled as a separate screen and it was very easy to set it up as an object by simply creating files in our checkout folder.
The next step may be, yes, the next step, let's go ahead and add navigation between each screen, so starting from the home screen in Hello world, we will most likely have a link here that says, "Hey, navigate to the box to navigate on the Expo router, we are using the Expo router link component link and I'm going to add them, let me." In fact, I reused this text field because it has some styles. I'm going to say change the text to check and instead of a text, let's make it a link. The link expects an href with the location of the web page we want to redirect.
To make the payment, we want to go to that slash and now if I press this payment, I will be redirected to the Personal Details page, we can't see anything because it's at the top, but in a moment We'll fix that, so now we can navigate from the home screen to the checkout and if I refresh, I can come back here and go to the checkout or, yeah, now we can see that the text with personal details is below the notch and here we have a couple of options: I would use a safe area context here to render the texts below the notch so as not to render them below the notch or what, we're actually going to skip this step and move on to the next one. immediately because it will automatically fix it for us, the next step will be to specify what type of navigation container this payment is because right now basically these payments and deliveries are still part of our Root Browser to define the payment as a separate navigation and in this case a stack to define it as a stack navigator where we can move back and forth between screens.
What we can do is create them. Underscore file layout. TSX knit design. The name of a file is important. should be an underline layout because this layout file is going to determine that we are going to wrap all of our screens inside this directory, in this case the delivery index and the payment, so here let's export the default function and say this will be the check stack, but check the stack and let's return what we can return through the stack component that is imported from the export router and just return this stack here. Come on, if I go to pay, I see the header with the index of thehome page we can go to checkout from checkout if we press next we go to delivery details here then we go to payment details here submit and we go back to staff yes not to checkout but when you wait a second at checkout it should go to the home screen of the router.
I think in that case, why does it go here in the payment? Let's try a link with your href also home and from payments if I'm going home. white redirects here what's happening on the web let's check so if I go to the home screen I can go to checkout next and here if I go to submit I go back to the personal information which is very strange but let's think about it a little later. add it so you know why it's not navigating home, this is like home to home, in fact, this one will navigate back, so now you'll see from payments if we press send.
I'm going back, yes it's weird, but at least we have some basic navigation between screens. and when we press submit we go back to the first screen so I think we are ready to do git add, maybe there is a dot in this directory so if you make a dot it will basically stay there or even disappear. at first, yeah, like that, I could understand why, because we could get them this stack, not the root stack, but this one, why not, it doesn't work. What happens if I use the stack here? See next, next shipment, no, yeah, weird.
I edit the notes for the end. Okay, now let's go ahead and start working on the design of our form. Here the first will be our personal information. On the personal information page we will have two entries, one for the name and one for the email and we will also have these types of cards that contain the information. I'm not going to stay too close to this layout because I think we can do better, for example I don't see the reason We have separate cards for separate inputs and for that reason I will try to group them on the same card to use the space on the screen a little bit more efficient so let's go ahead and open our index.ts because this is where we will handle the personal details of the user information so this form what we need is a text input so let's go to the components maybe before entering the uh.
For text entry, let's look at the card. A card is a component that helps us basically render cards with maybe even a title and background content, so let's go ahead and start using it. What we need is the card with maybe a card title. and the contents of a card, so from the native paper Rec let's go ahead and import the card and instead of this personal data, we won't need it, it will be a car title, let's render the card and the card requires, for example, give me give me. Style, so if I go to the card title in the properties, the title style can be oh, title variant.
I meant that it can be a large title, for example, so the title variant will be large or medium. Let's go verify personal information, maybe not even the title, but. the title doesn't need it that big big title okay that's better that's the title of our card and if we're going to use the point content of the component card, we can provide the content details here so that here we can have a text saying hello and let's see the text as content of this card to add some space between the card and the button. I'll simply use the style space in the parent component and provide a 15 pixel space.
Now all the components here will have a 15. pixel spacing between them that's something new in react native what else what else yeah I think let's move on to the card content and this is where we'll use text inputs let's go to the native role of Rack and let's find a text input, the text input is here basically import the text input and use it there, the first text input from the react native role and inside our card content, let's render the text input with uh, for example you can provide a placeholder name, you can also provide a label for example name and this label when Let's start typing it will be displayed at the top.
I think this is a very nice UI where you still see the label after typing something, so yeah, that's the label and we can add another one via email. I think for email. The placeholder can be something like a good example and let's also add the same space for our content container, so here, if I add Style and we make a space of 10, we will add this space between them, the text entries themselves, um, yeah, I think. That looks good. Another thing we can do is adjust the background color of a text input, so by providing a style here, the background color is white and here it will also be white, but hmm, yeah instead of color coding. from this we will use them from the theme provider that we define here paper provider with a film, in that case it will be very easy for us to make this application in light and dark mode, so to do it from react native paper we can take the hook with theme and we can get the theme using the woven theme hook use fim now instead of this white we can use film dot colors dot maybe background I'm not sure what background the card actually uses, you know because I want to make match the background of a card to the background of my text input, so maybe I'll also add a style with a background color to the card and now it actually matches the second input, okay, now it looks like this, but let me change my left with your coding now I have a coding YouTube channel which is great, subscribe to that development with Mr.
Shoya, what are you doing on YouTube? Hmm, so we have tickets, do we need anything else? So we have a name, we have email and Yes, I think we're good on this, on this page and we can press Next to go to the delivery details. Let's go ahead and do the same type of structure with a card with text entries on our delivery page, so what are we going to need? from Rec native paper, let's try to do it again to make sure we know how to use these Reactive native paper components, so starting with a card instead of handing over details, let's go ahead and render the card where we will have a Dot card.
Point title where the title will be the delivery address and the variant of the title. What did we have here? Big title. So what we're going to have, we're going to have a card. Point content with some text input imported from non-native but reactive paper. So the label of the first one, what information we'll need there for the delivery information, maybe City, what else, let's say, zip code, let's go with an address and maybe something, yeah, in a moment, let's go ahead, let's style them a little bit to match our previous page, for example, the content, the card content needs a style with a space to add space between the entries, then the text entry has this style with a background color, but for that we also need the theme, so the text input has this style them all and by theme we will use them use fim from the native paper Rec like this, so now if I go to this is the personal information, so we have this, but we need to make sure we give it the styles to our card also to have a background color, a lighter background color and a space with the root container of 15.
Yes, it is 15. Okay, from the delivery address we have the zip code address of the CD and maybe we can make some kind of check box for delivery. the shipping information, like if you want fast free or same day delivery, the component we will use for that will be a radio button, but more specifically we will not use them separately, but to use them as a group of radio buttons to have a radio button group a radio button dot group radio button yes let's import let's go to the delivery sex and import the react native role radio button now after the address should we create a separate card for Delivery?
Yes, I think in this situation it will make sense to have a separate stream. I'm going to copy this card one more time. And instead of the delivery address, we will say delivery options or shipping options instead of these text entries. delete them all. I'm just going to be a card whose content will remain and here we're going to render a group of radio button points and the radio button point element inside of it. The radio button dot element requires a parameter called value and label, so for the label let's start with a free value what will be the value of three and do the same for the hours as well.
I know that delivery is fast and the same day. Okay, now the radio button group component is missing the value and when you change the value, for the value you can't do that by using a state variable for dispatch. Oh, let's send and set the use state pink from react and let's use the value that will be our send and by changing the value we will call set send. No, you will have value. and let's send it to that, oh because it's 95, so let's preselect free shipping and yeah, we already see it on the screen, so now if I'm going to change too quickly, I'll change there too, yeah, I think. for this use case it's really good to have separate cards for our this is where we're going to type something here is where we're going to select something and then we have the next button um in cases where this is going to be a very long page that we have to do Sure yeah, for For example, if I'm going to duplicate this a couple more times like this, we'll see that the button is already off the screen, in this case what we need to do is make sure that our screen is scrollable to react. native, let's import the scroll view and replace the top view with a scroll view and now we can scroll between them, but the thing is that with a scroll view now the style must be the content container style, yes, and for maybe hide them, the scroll indicator is shown. vertical scroll indicator false yes perfect now that we're this way let's make sure that everything is basically accessible.
Let me go ahead and delete the last two cards that I added there because it only serves to reuse display Longs. forms and how we manage them using scroll views and yes I think it's safe to just replace it in the other forms as well, for example in the top view index replace it with a scroll view make sure where you close it is also scroll View and import from react native foreign and the same can be done for our checkout instead of seeing a scroll View closing tag and import it from react native check below from the delivery information we can press next and here in the payment information, let's go ahead and start defining through entries for the data on this page as well.
I'm going to delete what we don't need there. We just have a submit button and actually from delivery, let's grab the card code with these text inputs. Let's be a little lazy and reuse some of these fields, let's take them to payments.ts also the use. theme because we need to make sure we import the movie here and use a theme like this and let's navigate to that delivery page and we're on the payment information, let's adjust the card because we'll need other fields and the title will be the payment details. The first text entry will be the card number, maybe you can provide a placeholder, like I don't know, for two by two for the zip code, no, we don't need the zip code, we need something else here, let's make a tag, tag, what, um. due date and something for security code security code due date is not actually a text input due date is a date picker so let's see what reaction native paper has for dates so If we look at them, do you see anything with dates here and Remember I saw the date picker.
I don't know, they don't really, yeah, it's actually an extra thing, so let's do it for the due date. Let's just provide a placeholder with m M YY and we'll initially handle it using some

validation

rules and then maybe we can find it and replace it with a more appropriate um input type. If we put the expiration date in the security code on the same line, we could place them inside the same view which will have a Flex Direction style row. import view from react native and if I go to the last page, yeah, we see something and maybe Charles needs Flex one and the same for the second Flex one maybe something uh um for this view, let's add a space Gap 15. yeah and here you can play like you can make the expiration date entry twice as big as the security code or we can make three and this one too yeah I think this is better awesome and lastly we can see our other component that can help us.in this form there is a switch, let's use a switch to indicate if a user wants to save their payment details, so what needs a switch?
Well basically the switch let's do it after this view as I think it should be in a time view because we have a switch and then we have a text, we will import text from the native paper Rec. What will the text say? Save payment information. Not really. First of all, let's style it. No, not really. I want this switch for this use case. This switch actually turns something on and off when saving user information. I think it's more of a checkbox, so let's use the checkbox. It also has a checkbox element and I think instead of a full view we can use a simple checkbox element imported from react native paper navigate to the last screen save the checkbox element save the information status checkout checked or not, it will depend on whether later we will implement that tag variant, there is a position where we want to show it, so position if we do it first, it will be at the beginning, yes, okay, so if it is not checked, I don't I like it a lot because it's not very visible, but it's a checkbox, but to be honest, that's how it works on iOS, so in that case.
I'm not going to lead positions because it makes more sense to fill this out here and mark it here, all good, perfect on Android and also on the web. I think it should look different, so if I go to checkout then yes, here is a proper checkbox. Yes, I was looking for, we can add a Max move to our cards and make them on the web so they look better, maybe we have to do this Max move on the entire content container here and if we do a self centering line. foreign, but in this case it needs 100 percent width to be viewed on mobile devices and on the web as well, so now we can see that this is responsive and if our screen gets smaller, it automatically adjusts, but if we have a screen blurry, no. will be displayed in full width, only 300 pixels will be displayed, i.e. 500.
So you can do the same style of content container, for example, with our scroll view payouts and also the delivery, and now all the Screens will also look good on the web. Okay, okay, so we have good progress. We've added the inputs, most of the inputs that we need for our checkout form. Maybe by then we'll add and work with other input fields as well as our input types. well, but before I overcomplicate this tutorial, I want to cover the next part which will include managing these forms using the react binding form and also validating them using Zod schemas and after that advantage, if we still have some time, let's go to analyze it. add additional fields to the existing form and then it will make more sense because we will already have everything connected and we will see how we can adjust it, so let me go ahead and do a git add here git commit minus m forms UI and we are ready to start with the next step using the graphical hook form to manage these forms, give me just a second, I'm going to get some water and we can continue, I'm back, it's a good idea, but you still have to have this index, so what you can do is we can change the index name to personal, come on, personal, uh, in the layout, yes, you need to change the index to personal and if we're going to pay, we'll land on personal, but if we're on the web, we'll navigate to pay. it will automatically redirect us to the staff because that is the first screen and we don't have an index, yes, that's good, yes, I think it's very useful because all the screens now have payment and personal delivery.
Ok, now we move on to the interesting part of this tutorial. So far we have implemented our multi-step form UI, now it's time to manage these forums every time the user types and completes the text entries, we need to know the details about what he is writing, we also need to validate each time you hit submit to make sure the data is valid and doing all this without additional libraries can become a really complicated task to have all this validation and all these error states etc., for that reason what we're going for. What we need to do today is use the react hook form to manage the form in combination with zond to validate our fields based on a schema that we are going to define, so let's first open the documentation for these two libraries.
This is the library that we are going to use to manage the implementations and in the introduction, this is where the documentation is primarily aimed at the react app for the web. They have some documentation here for react native, let's be able to. Start from here, but I'll show you how we can do it a little better by creating some custom components that will help us do that because in React Native it's a little more verbose and contains a little more boilerplate to manage the inputs than on the web, but that It's not a problem because by making some reusable component at the beginning, it will be very easy for us to reuse it, so react from the link form, okay, let's install the library.
I'm going to do that using npm install react hook form let's go in with the first library then I said we're going to need Zod .dav here's the documentation let's do Zoom in dark mode and we thought we can do this typescript and schema based form validation we're going to define so what I wanted to show here I don't think is forms integration yeah we have a link here for forms integration to show how we can integrate zod with the react hook form to do that we need an extra. component called hookshape solvers which will allow us to establish a connection between react hookshape and Zod, so let's go ahead and copy the name of this hookshape slash solver package and also install it along with Zod so that npm install hook form bar resolvers and Zod is also fine, where do we start to manage the form or show you the Zod?
I think the best place to start now is to first define our results schemas so we know what results were returned as these are a small schema we define what our data look should be like and using that schema we can use it to validate inputs and automatically get error messages based on things that don't match in the schema and we can also infer typescript types which we can use throughout our application to have type saving validation and forums, so for that let's go ahead and create a Source directory in our application where we will save all of our source code including our schemas, so in source I'm going to create a new folder schema and invert the schema, we're going to create a new checkout file. dot scheme TS Ruby x no, it's TS, it doesn't have any GSX bears, so let's take a look at a small example of basic use of the Zod scheme.
We see that what we have to do is import Z from Zod and then use the Z point object. Define, we can start defining the shape of an object, for example, the shape of a user that contains a username of type string , so let's start by importing Z from Zod, define and create separate schemas for each step of our form. So, the first outline will be our personal profile. The personal information will be the object of point Z and the fields that will contain our personal information. One of them is the name and the name will be a string of dots Z and the number one. it's going to be an email that can be defined as dot Z email.
I think it's a dot chain email like this and now if I export this, I don't need to explore this, um, okay, okay, before to go ahead and use this person. this Zod schema within the context of the hook form, let me play a little with this schema and see what we can do with it, for example, if I'm going to have an object, let's say an example with a name and let's say a fake email, we can use this method of parsing personal data points where we can provide a JavaScript object and return what we are going to receive.
We will receive a typed object that has the name and email, so now what can I do. I can probably run this file, let me see if I can do it using the Source node Dash Scheme The Dash payment scheme cannot use an import statement outside the module. Do I have to do anything special to get the web version? No, if you are using the Expo router, you can simply run the application on the web by pressing W on your development server and it will run on the web, but what I was doing now here is running this file that will try to parse my personal information. data with a fake email and what we see here is that we actually see a Zod error, the validation code is an invalid string and we see that the path is email and if you provide a proper email, we will try to make the node npx test again. with the schema we see that the information has been parsed correctly and does not have any errors, so with this approach yes, like what we do, we define with schemas and then we can analyze the data to make sure that it meets the requirements of the schema that we provide and if not, it will throw an error and it will have a very descriptive error message like in the case where the fake was not an email, so if we look at this we see that the messages are not valid. email you can also adjust these messages by providing here in the email property the message, provide a valid email and if I run it again, we will see that the message is, provide a valid email, so from this place where we can adjust the error messages that we will show later in our react hook form, but as you, uh, and the number of things, of course, infer the type of our objects that we are managing there, for example, if we want to write this object of information with let's say the type of personal information, what we can do is define this type of personal information equal to point Z infer and here we can provide the type of personal information, let's call this personal information keema and this type of personal information scheme now We can use this personal information to define it here.
Personal information scheme like this. Now this personal information schema was automatically a type defined and created automatically based on the object that we have here and I think if we provide here a minimum. one in that case the name should not be optional I think why is it not required is it nullable is it optional no let's do that uh here I'm going to clean up the last few rows that we were playing with and I'm going to export these two things from here export constant schema and export personal information type let's go to the application, check personal here and start managing, yes, the next step is to start managing the form that we have here with two inputs using the hook form, so for that what we do What we need is inform import, the usage is use form hook or use form hook, react form hook and yes the hook is called use form, let's go ahead and add the top of our screen, let's define this form, use four using this uh by By using this hook, we basically define a place where we will manage our form.
This hook will return a couple of things for us, for example, it will return a handle submit function that we should use to wrap our basically when we press the submit button. from directly calling the function what happens when the form is successfully submitted, for example to go to the next page, we need to unwrap this in the controller's submit function and what this will do is basically every time we press this button, First things first, it will validate it. the form is um it is correct and only after that it will go to the next page so now on the next page what we will also get is we will also get some data this data will be all the console fields all the fields of our form data Form fields let's do it like this, the data at the moment is not going to work and if we go to look here, I can press next and we will be automatically redirected to the next screen, that's because we didn't provide you with a way from the form to validate the input fields to do that, what we can do is provide here in the form use an object and we're going to provide the resolver and the resolver is how we want to validate, validate our fields and using that custom resolver, let me check here in the react hook form documentation we see Zod and here we show that yes we need to import this Zod solver and using the Zod solver imported from Zod hook form solvers we need to provide here the schematic and the The scheme is the one we definedhere, the personal information schema, so let's import the personal information schema and also the personal information type because we will also need this personal information, the schema will be the Zod solver used for our application and if I want maybe a little later , yeah, now, if I'm going to try to do the following, nothing will happen.
We look at the records. In reality, nothing has happened. Why there are no errors. Nothing at all. Basically, our control dispatch function tries to do that. validate the data that we were trying to send and it is so that it fails the validation based on the personal information schema and the form returns some errors, how can we get those errors, we can get them by destructuring the state of the form and here we have errors, so if you just do console log errors you will see that when you press next here, when you press next we see that the errors are an error for the email, the message is required, the number one is for the name, the message is also required, okay , that means we can't move to the next step because our form is still buggy the problem is that right now we haven't connected our text inputs with our form here with our form from use form to connect it with our form what we need The first thing we need to do is a couple of steps: Basically, we need to make these entries text entries.
We need to make them controlled by them. Use form and to do that we need to destructure the control from a use form. You should import a component called controller from the react binding form. Here I'll show you step by step and then we'll extract it into a separate component because it's a little repetitive right now now that we have the react controller component. link form and this control here, what we can do is go to where we have our text input, add some space before it and start by rendering the controller component like this, the controller waits for the actual control, which is the way in which we connect the text input. with our form because this control comes from the use form it also needs a name so you know what the name of the field we are using here is and it needs to match one of the fields in your schema for example name and when it has a render function the render function is here to render the actual text input so if I take this text input here put it in the render and go back to null control what's happening see yeah let's try to write something if I press next if I look at the error messages the email and name are still required as well which means it is not finished yet as we have not connected to the controller with this text input to be able to connect it this render function will give us access to field properties, such as field properties.
What is the value of this field? The function we should call when we change the value and the blur event. We take these three events and send them to the text input like this. First, value is the value of the change we make. We'll connect it to the shift text because that's the callback function from the text input that the function will be called with a text field with a text string and in blur we'll just say in blur now if I'm We'll do one, two, three and we will do the following, we see that the arrow is only for our email, the name has passed validation, we can test that if we make our email optional or nullable, nullable and if I make the following email required, nullable, optional, yes. optional and it works, but if I'm going to have any value, I won't move on to the next why email is optional.
Curved before, no, it doesn't matter, we actually need it. I just wanted to show you that the name and password validation, but in case it doesn't pass the validation, what we want to do is visually show that somehow on the screen a way to understand if a text entry has an arrow or not is to use the object that we see here and that we get. the Status Errors form but this will contain errors for each field, in reality the controller in addition to the information about the field will also give us information about the state of the field and that information is, for example, the error, so now, using this simple error, we can provide some properties. for text input eg error this should be boolean if i make it true it will show in red yes then error Dot.
I heard that message, no there is another property besides error like invalid invalid so for error which is boolean we can send invalid error message and for error message what we can do is yes if I delete it, we see that it shows in red but it doesn't show the actual error message. Let's use another component of react native paper called auxiliary text. andThis rendered auxiliary text is usually used in conjunction with a text input and I will do this by wrapping them inside the view and after the text input let's place the auxiliary text so let's import the view from react native oh it's here View and from react paper native we need help text now in the help text the type is error the visibility will depend on this invalid field and the error message will be the dynamic error.
Message can't read fine message Define I think error question mark message because error is not always check and now if I go to do the following we see required perfect required so with this we also have error messages in our Controlled text input hmm. I was thinking why yes, for example if we look at this value I see that the type is any the problem is that right now our use form doesn't know what data it is working with, it knows how to validate it but it can't understand the type of those data, what we can do is provide it. with data type to use form as personal information and this is a type and that means now the value will be a string because you know that the value with a name name is a string and if we used here a number it automatically understands that this value is a number and it will automatically show us that, hey, maybe you're not using text input correctly because the value is a number and when you change it you should also get a number, so that's very cool, it's very powerful where just the outline gives us helps validate our text entries.
Let's say I'm going to go back to the string here because the name is actually a string and now, I think we're ready to do the same thing for the next text input, so it will handle the email, but like I said at the beginning, use this hook erected in the form of a native react hook in native Rec is a bit verbose since this handler has to wrap all of our inputs with a handler, so now what I would have to do is copy and paste it. again for the next text entry, but yeah, it will get out of hand because if I'm going to change something here, I might forget to change it somewhere else.
What I think would be a good idea is to extract this controlled text. go into a separate component and by submitting just a couple of fields like what's the name, what's the control, etc. we can have a much easier component to work with in our forms, so let's go ahead and into the source let's create a new folder for our reusable components and here we have a controlled input dot TSX let's export the default function controlled input and what should it return basically from the previous page let's copy everything here including the controller, let's bring them to our page here we will need to import a controller from the react hook form we will need to import a react native view and a text input and auxiliary text from the react native paper text input and auxiliary text the theme we need to get it using the use theme hook in the part top of our component and yeah, and that's it, now the hard part, let's see what properties the input of this control will get to make it really reusable and easy to use.
First, let's define the type of our control input props which will basically be an object where, first of all, all we will need is the control here, so the control is of type control which we can also import from here. Now we can take this control. Dynamically dynamically from properties like this. Controlled entry accessories. Now we no longer have the red warning here. What is going to happen? will be the next part to which this name will be dynamically sent as the name of the input that we want to render, which will also be a dynamic property and it will be a string, we will destructure this name from here and replace it with the dynamic name. in our controller, the rest of the things like the placeholder tag style value, no value comes from here and the text change too and yes, the free beasts come from here, but the placeholder tag position, etc., are also properties that will not be styled.
Do the same for all of them, but the placeholder and label will also be properties that we will receive from a parent component because all the text inputs will have a different placeholder or a different label, but instead of manually adding all the properties What we want. adjust from the text input here what we can do is say this controlled input extends how we take props from the react Dot com component and here we need the text type from the text input component and this way our control yeah and now our control-driven input props will contain the two custom field controller names and also all of our text input properties.
Now, when we destructure it, we can take the name of the control that we can structure and we can put the rest of the properties that will be. sent here on that text input, input props now with text input prompts can be just the structure here instead of placeholders and text input prop labels like this, the style we're going to be the same For all of them, we want to change the background. The color value comes from here when the modified text looks good in blur. Yes, I think everything else comes from the controller now inside our personal TSX.
Here let's import our newly created controlled input from our components and use it just below this controller doing rendering the control input, the control will be this control, the name will be name and what else we also need the placeholder and the label so let's put them here, so just by rendering this component with four properties, we're basically replacing everything we had here in 25 lines because all of this logic is inside our custom component, controls input which just wraps a text input inside a controller and it successfully sends the properties there, so now what we can do is safely delete our previous staff controller. .tsx and instead of the following text input, let's transform it into a controlled input where we have a placeholder, we have a label, we have a style, which we don't have, we don't need to specify the styles again and again because it is managed by the controlled entry and we also have to send here two additional fields, control and name of a field, what is the name of a field, it is email, now like this, let's update the controlled entry page, RR, no, let's go to checkout and now if I go to press next we will see that we get the error messages on both the name and the email which I am going to say for them here and press next if I am going to say I don't know Vadim then please provide a valid email and this error message comes directly from our Zod schema we can do it like this and if you provide a real valid email here it will work and we can go to the next page so it does a lot of things but To simply summarize what we have done now we start by defining the schema of our data where the form will be managed.
In this case, this specific form will have a name and an email. We define what this data should look like, what validation it should have. data types and what specific formats they should be in, we also provide custom validation error messages and then we use this Zod schema inside our use form to use it as a validation method now with this use form we make sure to wrap our inputs inside the controller from our form and when we press the button we call the submission identifier which we also get from the form and this submission identifier will create a scheme to validate all the fields and it will call this function only if the fields are validated or show the error messages . on the screen if it is not validated if there are some errors like this, perfect, so let's go ahead and commit everything and we will do the same in the next two forums for delivery and payment.
I recommend it, I highly recommend it. to pause the video and try to do it yourselfFor the next screens, all you have to do is create new schemas for both screens and start managing the form using the form hook on the personal and payment screen and in the meantime, I'm going to commit. Oh, hi Ahmed, thank you very much. Could you create a journaling app? Native Rec. It is a good idea. I think I'll add it to my list of ideas, so let's go ahead and do the same form management form validation for the next form. delivery, for example, if we pass this on forwarding, we will have the city postal address and shipping options, it all starts with the definition of the schema, let's make the delivery form here, first of all, let's export our Zod schema for the information delivery, keema to be created. using the Z point object because the information is an object, you start what will have first City, it will be a string of z points.
We can also make a minimum length of one for the zip code. Point Z should be a string. I think it can. be a string, let's start with the basic validation and when we can go back and see how we can improve the validation by just adding rules to this scheme, so zip code is a string address as well as a string and a shipping, um shipping, let's see Zod for enums Maybe zodenums is ok, then for shipping we can use Z Dot enum and here we can provide the possible values, for example free fasting or same day underscore.
Well, this is the basic outline for our delivery form. We also need to infer the type of one of these objects, so the type delivery information will be inferred from our schema like this, now let's move on to our word delivery page. Here, what do we need? We need to use hook, use form, react na. I always forget the hook reaction form. we will need the solver from the forward slash hook shape solvers the zod solver is like this oh we saw the solver and we also need this schema in which we define the delivery information and the delivery information schema of our payment scheme Okay, now let's define the form using the use form hook, let's say we want the solver to perform validation using the Zod solver's delivery information scheme.
Let's say this form will manage data on delivery information of this type and we will return that control and what else do we need here we don't need the errors because we are managed at the level of a field. I think just control, yes, maybe now we are also going to need the custom component called control input and instead of this text input we are going to transform it into a controlled input where we only need to send two additional fields, control and name of this field, the name of a field will be City, then we have the zip code, let's turn it into a control.
Enter here we have controls and for the name we have what is the name in our schema zip code like this and lastly, this is also controlled. Enter for the address, send the control layer and the name will be the address now if I go to pay. if I give some values ​​here below and if I go to press next now no yeah that's what we also need the submit handler so on the button at the bottom of the screen we go to the next page only after handling the shipment. only after validating with the form it is valid, so now if I go to press Next, we will see that the required postal registration address of the city is required, and so on, if I am going to fill them out, I will not do it yet. can I continue because we haven't validated the shipping options yet um the shipping options field because this is no longer a controlled input this is a controlled radio button, let's say let's go ahead and remember what we did last time to control a input , we imported the controller from the react hook form and wrapped our component, in this case, our Rado button group inside that controller.
I mean, we didn't wrap it directly here, but we put it inside the render function, so in render we will render the radio button like this, the controller handlers of course need two additional properties, the control and the name, and the name is in the schematic, we made it as a send, now the render will receive them. Field status, including value, field status, why typed. it doesn't suggest a value to me, oh it's not a field state, it's a field value on change and I don't think we need to blur the value here. Basically, at this point we should stop using a local state variable.
I'm even going to delete it. here the submit and submit set which was a local state variable now it will not be a state variable it will be managed by form so for the value of this radio button we will use the field value and for update we are going to do it to use on change and the value here is a string, but it should be three faster on the same day, okay, let's do this, we don't show the error message yet, so let's take the Status field as well with them invalid. and error and we will use them for probably what we are going to do with it if we show a help text above the radio buttons help text let's do the same as here, like help text type error with an error message and help text help imported from react hook form, can we somehow skip the personal info page because I always have to add it to do that?
What I can do is just put our delivery as the first screen here, see, see, oh, come on, is it for a delivery help text here not from the reaction book form. I need to import it from react native role. Check and we are on the delivery form. If I press Next, we see that the error appears here as well and we actually need to select one of them, how would I do that? we add default fields, for example I want the free one to be selected automatically. I think we can wrap it in the use form hook, so inside the delivery file use the form hook here could be something like defaults and for the submission, let's say. oh look because it's written because we wrote it with this typescript you know what shipping can be there so I do it quickly if I update if I'm going to pay the first one was automatically selected I think I want you to make the payment for free and it's Se automatically select with free and if I press next only now we can go to the payment information, this is how we create them, how we implement the form management and also the validation for the second part of our forum for the delivery information.
Okay, now what you can do is extract this controller into a separate controller like we did with a controlled input that will be controlled with a radio button, but then I don't want to do that because I only have it here, so it's okay that the input controlled is used much more frequently, so it made sense to remove it. in a separate component, you can do that too. I'm not going to do it just because I want to save a little time, so we're done with the basic validations on this page, maybe we'll come back to add. some more custom validations when we're done with the next form, but for now let me do git commit minus m um delivery information perfect form administration the last step is our payment information, so first in the design I'll put the payment information in the first screen.
For now, if I go to hit pay, I'm going to be redirected to the payment information because this is the first one here, so payment information, let's open the payment information page and we'll also need to open with the outline. Because we need to define a new schema for our payment form, let's start as we did before by defining the payment information schema using Zod. It will be an object and what information will it have. It will have the card number. Chain of Z points. It will expire. date look I'm going to make a zero string for now and just to connect everything together I see the security code Z dot string CQ write your code and lastly we're going to save the information as a boolean z dot okay so Let's also make sure we export. the payment information type using point Z infer the delivery information type perfect now let's open our payment.tsx component and here let's start by importing everything we need we will need the use form react to the form we will need the Zod resolver hook the solver Zod bar forms and we're going to need payment information and payment equipment to outline our payment scheme.
Let's go ahead and define our form. Let's use the form here. We already know that we want to define the type of our data as a dynamic type there. and as a solver we are going to provide the sword solver using our schema, okay and we are going to recover here that control and sending the identifier for sending the identifier. We already know what we have to do. We're going to wrap our function from its own press event in the dispatch controller and if I press now nothing happens because we get errors and the control will be used for text inputs because we're going to switch from text input to controlled input and we're going to provide here the control and the name, how is the number, yes, it is the number, so for the due date, it will also be a controlled input and for the name, it will be the due date, actually we don't need any additional styles. for this one we need the flex hmm, we'll see what it looks like, so let's do the last thing, the security code also controls the input, yeah, um, let's see if from the input control now you don't have a flex one and it doesn't.
Look really good there, so if this view will have Style Flex one, yes, I think it works, I hope it works because it didn't break in our places, but we'll see a little bit later, for example, in the first one, the card, the number. I didn't break it so I hope it's okay and lastly all of our inputs got checked and this checkbox we should also make it a checkbox. We'll do it using the control component, not like this. First we need to import it from the react hook. form controller and we will add it here specifying the control, the name which is save information is how to save for yes and where to render will be this checkbox what payment information, oh wait a second, I think I made a mistake here, reverse schema because I need to infer the type of payment information schema, yes, now save to make it work and the state whether it is checked or not will be determined by the form value, so the form value I will always forget if it is not feel like the form. field, so the value now, if we look, is boolean, so here for the state, we need to send a check to unchecked and we will do it using a value that is true and then it is checked; otherwise it is unchecked, no it is not checked, if I press, nothing happens. because we should do it on press, we're going to call the change on shift and we're going to revert the value.
Yes, now it works to save information. Now it doesn't work. Now redirect to home page. Actually, it is in the design now. We are going to put the payment on the last screen and if we are going to refresh our page and go to pay, we will have validations for the reverse screen, we will enter the email name below for a delivery. we can't go to the next, we need to provide information about CT address and so on and here we can't go to the next screen, we need to do this and save the payment information, submit and we are on the payment page.
I do not do it. I know why it works now, but it's good for us foreign validation for last step management in our multi-step form for payment details, so let's go ahead and do git add git commit minus m payment information form management , okay, what we have now. We have free standalone forms that all manage information about what they need, for example, the first one manages information about personal information, then we move on to the next one, the other manages information about delivery and the last one is about payment, we think that's it. when we get to the last page and press send in many cases, at this time when we send things we need all the information that we covered in the previous steps, the problem is that at this time on this payment screen we only have information about the payment information , we will somehow lose information about the personal and delivery forms because they are different screens, so to manage all of us separate independent forms as a complete flow, what we are going to do is use the react context to manage this data in a level higher than the screen level.
What we will do is define our reaction context which will contain all the data about personal information, delivery information and payment information, and will wrap all of our screens. from our checkout page will not wrap the entire application because we only need these screenspayment contain this information and then on the last screen, when we press submit at that point, we will have all the data collected in our react native context. so for that what we have to do is create the context, let's go ahead and in the source create a new contexts folder and in the context let's create the payment context dot TSX first, let's define the payment context, let's create it using Create Context which It is imported from react and we will initialize it with an empty object to make it safe.
We will also make the payment context type, which will initially also be an empty object, but we will be able to specify the type of this context right away, so now this is a payment context, type okay, the payment context right now contains two things: the provider and the consumer, so first of all, using the provider, I am going to export this default function which will use the payment context provider and check context.provider, it will send the value to this provider which will initially be an empty object and inside this provider we are going to represent all the children that the payment context provider component will receive, so here children oh okay, okay, let's do a test and listen to ABC now.
I usually also like to export a custom hook that will give us that will consume this checkout context and that hook will be called. Let's also export the constant usage payment context which will be a custom hook that will simply call the usage context and provide the payment context anywhere and then instead of importing two things, the usage context and the payment context, We're only going to import one thing, this payment context, now that we have a standard model of our payment context. We need to wrap our screens that depend on this payment inside this function inside the payment context provider, the screens, instead of wrapping our root layout the same way we did with a paper provider, do the same with a provider of payment context instead of doing that.
Basically, I don't need information about the payment form on every screen of our application. I just need it on the screens inside the checkout folder with delivery and personal payment for our controller to encapsulate the screens inside our underscore layout from the checkout page to just If we have these components, they depend on the checkout context, so let's import the payment context provider from there and tune our stack with it now to understand if our screens like delivery and personal payment. If you have access to this context, we have here a proof of value. Let's move forward personally and at the top of our function I'm going to remove the errors.
Let's do a constant test from but let's use the checkout context just like it was imported from here. Now if I do the console learn test we should see the ABC warning. here, which means that our screen has access to this value from the context provider. Okay, now what we can do is add state variables for our personal information, for our delivery information, for our payment information. I'm thinking here if V should be state variables. in them if we should manage the state variable of the already validated data or if maybe we should move a full use form to the context provider.
Actually, I don't want to do that. I really want to leave the low level form management to everyone. individual screen and in the context provider here I don't want to think about forms I want to think about data, so in this situation I will have free state variables, one for personal information, I will make personal just to keep it short, don't make it information set personal personal information set personal this will be a use state and the value will be null initially, but the type will be imported from the personal information of our results schema, so in that payment context the type will be will be personal information imported from our schema, the same thing we will have for the delivery of the delivery set, this is going to be delivery information initially null and I think we should also say it, so this would say should do either null or null and lastly it's going to be our information payment set payment information payment information or null and so now our value will include all this data basically personal information set personal information I'm not sure if we need the values ​​to expose the values ​​that we can expose the Setters because we will use them to store data in the global context like this, it should be inside an object like this and now our context type will include this personal set which, if we look at the personal set type, it's easier to react and send the set action. and the set action type will be personal information, then we will have a set delivery which will be a react send set action delivery information and the same for set payment, this is payment information, maybe also null Also, if we want reset it, maybe yes, yes or no, let's not like it, okay.
Now the default creation context here will say that, hey, we need to provide a default configuration, um, payment and personal settings, etc., so let's make a default configuration. one that will be an empty function uh it will also set the delivery and lastly it will also set the payment uh and let's also expose a function called on submit all that will be called in the last step so fulfill all sending the multi step form and let's register here the personal console let's register here the delivery and payment so let's also export this in the shipping function but we need to specify the type so in the shipping type everything will be a function which is not returns nothing. and the default value will be like this, you don't like it, it should be null, no, okay, okay, so export free centers to save a personal set, save a delivery set, save a payment set in our global context and then a function.
It also does all that, it displays well and we will basically write all these details to our console. We can go ahead and connect this information to our actual forms. The first one is our personal and here in the context of use and payment, let's get the personal set, uh and this. set personal we will use it with this data the data function on the next page is called by the submission identifier this submission identifier will send the data and this data will basically be of type personal information now because it is of type personal information we can go ahead and set it In the context of global payment as a data set personal data the same should now happen on delivery.
Here we will have them use the payment context and we will receive a set delivery. The next page will receive data with delivery information and we can use it to set the delivery data now in the payment here we will receive data of type payment information we need that constant use of payment context and use of payment context will receive a set payment and also your own send function the first step is to set the payment as data and the second is your own send all of which in a real scenario will actually be in a sync function because normally you have to wait to send this data to a server and that's It's not an asynchronous function, so let's change this from a normal function to a sync.
It should be a promise. If we promise Dot Boolean and return true if everything goes well and return false if there was an error sending it to the server. Maybe so here I don't do it. I don't know the promise dot resolve false and also everything will be synchronized and return true now in our last screen in the checkout screen, we will const re uh success equal to a weight when submitting everything and here we can check if it was successful is it true only when we redirect our page; otherwise let's make an I don't know alert.
The alert failed to submit the form for some reason and this error is not necessarily related to the form validation because at this point we know that the form validation passed, this is actually a uh, this is actually due to um, yeah there are some problems sending the data to the server, maybe the user does not have internet connection, so send everything, let's check the name by dim email next, we will also keep an eye on the console because in the end we should display this like I want free delivery maybe fast delivery next and payment information like that and expiration date like that and security like that and save and send now it says send the multi step form we have an email we have an address but the payment information is null you know why what is null is not because we are calling the configurator which is a state and sending all the functions basically one after another, but we must remember and in fact I had a coaching call with one of the startups that I am training and that was the problem that I was explaining to them to keep it up to date because updating a state variable does not update the actual state variable. value immediately will only update it during the next repeat, so basically in this case we are scheduling the set payments to update and we will also meet everyone when we call it during the same time as if we don't already have it, so such maybe maybe also meet all hmm maybe we can send this data to shipping room because this is the last step let's try that even then, I don't like it, better think with challenging one, how is it done correctly?
One way would be to send this data to the shipment itself and then send the data here and yes, like in them in the payment context to receive them here as payment information, but in that case we are not going to have a status for the payment and it is a Kinda weird that all the steps have a state variable and the last one doesn't have a send all. I could do it with some kind of awesome statuses and some kind of usage effects, but I don't see it very It's a very optimal solution guys, foreign status, maybe I'm going to leave a paid status, but I'll also receive it here as information payment, payment information, so now, now here, I'm going to make a payment information set and I'm not going to depend on this payment in this method, but I'm going to depend on this payment information variable because the status may not be updated yet , but I'm pretty sure that what I receive as a parameter will be the most recent information now. in the payment here I can leave a payment statement but here it is optional because all I have to do is send the data to the send everything itself and we will send everything here we will receive payment information of type payment information let's check right now If I save now , we see a multi-step reminder form with this data, email and name, then address, city zip code and shipping due date number, we save the information and security code, so now we see that when we press submit on the last step, I actually have access to all the information we covered in each step of a form until the last part.
That said, I think we're done with implementing multi-step form management as one where we get data. of each step of uh of that multi-step form, so let me do git add git commit uh, okay, what else, what else, what else, what other things are you interested in? Should we improve the form validation rules a little bit because there is a lot going on right now? of them are, if we look at the schema in the payment schema, a lot of them are just strings, so let's take a look at the Zod documentation for strings and these are some of the specific validations that this min and max will specify.
There are external validators. contains is after and so on, so what do we want to do here? For example, regular expression is great. What we see here is how we can provide the default error messages for them. i want to adjust it so that it says let's say in the name when we say string for the required error, we can say that the name is required and now it will actually say a more descriptive error message instead of a default required error message, you can also do that, what else ? Can you do using the length? What we can do is on the last screen for the security code payment information.
I think we can specify the length for free because all security codes must be three digits, so if we provide a message security code here as well. should have free three digits, what else can we see here? This is for days, but we're not going to directly look at dates, IP addresses for numbers you can specify greater than less than if it's positive, negative, if it's an integer, so it's very very powerful like, oh, so the optional are optional and when you put it inside the type or you can make an optional point, look with what we have come up with, I think we can use the join to merge all the data at the end into one. uh, right object, so if we have an object, one base master is merged with another one, for example, if we go into the schema and if we want to define a schema for our payment information, refer to the information schema which will be a schema ofadditional etc, what we can see initially is if we press next here we see the validation errors, let's go ahead and fill this one out, for example, if I provided an invalid name, it immediately tells me the password and it will make sure to combine the passwords and I think you should hide them, but that's not the biggest problem now with a mesh, I'm compressed below and we go to the delivery information, after filling the delivery information with your details, you select the shipping option, you can press next to go to the last step with the payment information here if you just press next you will see that the card is the card number which is validated correctly the expiration date should be something in it it should be something in the future it will validate it at same as 24 and for the security code it must also be a three digit finding. on Android too and also on the web here on the left you will see it on the web and it will show the same error messages that we saw before.
I hope you enjoy I hope you enjoyed this tutorial and if you did, make sure to subscribe to the channel and hit the notification bell so you don't miss our future videos because we will be live every Friday with new tutorials. I also want to tease something, so if you're watching this right now, stay tuned to our academy.nojs. dev, which is our premium course, stay tuned over the next week because we may or may not have something special for you and if you're a vv up to this point, message me, let me know because I might have something interesting. for you and if you are seeing it here it means that you are dedicated to learning full stack mobile development.
Alright guys, have a great weekend ahead. See you next time with a new project, bye.

If you have any copyright issue, please Contact