Building a Full Stack Workout Tracker with React Native & MongoDB

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
B for the Tex tack for the front end we are using rck native and of course we are using Expo and the we're using the latest SDK 50 version and also Expo router for managing the navigation between different screens on the back hand we are using we are building a graphql API using ibam stabs then and this graphql API that we are building is connecting and is pulling data from different sources on one hand for the exercise data source we are using an external rest API called API ninjas and for our custom database where we store information about sets we are using mongodb which is a very scalable and performant uh nosql database this project is sponsored by IBM stzen and if you're not familiar with them uh with IBM staben you can easily build a graphql API in literally minutes by running a simple command uh we're using it in today's project so if you're interested you'll be able to see uh See IBM stabs in in action before we start I want to mention that this is actually part two of a project uh today we are doing part two if you're interested in following the part one where we have built the user interface we set up the graphql API we are pulling the exercise database and we are also reading data from our mongodb check out the first part which is on our Channel on YouTube uh or you can follow the URL that you see here the plan for today is going to be to uh yeah previous time we didn't manage to build everything so I decided let's do a part two of this one and also let's do some more advanced things like pagination a lot of other interesting things that you're going to learn today so the plan is following we're going to start by Saving new sets in the database because we implemented reading sets from the database but we need to also save them we also want to link sets to a specific user because if you're building a multi-user application you want to link somehow the performance and the set to a specific user we're going to implement charts to so to see a feedback we're going to implement searching and filtering and finally pagination to be able to scroll and load more exercises from our API so a lot of interesting and cool stuff I'm pretty excited if you are also excited uh and want to follow along make sure to download the updated version of asset bundle following this URL assets. noas dodev workouts and if you want the source code to start from the same point there are two option you are either going to check the GitHub branch in uh following the link in the description below um there is the workout repository and there is also part one branch that will be uh will contain the code that we're going to use to start today also the second option if you don't want to go through the GitHub if you don't want if you don't want to to do that you can simply download the updated asset bundle and there I'm actually including the source code and the repository from uh part one and that's probably going to be the the easiest way and I'm going to show you how we can run and update our API keys to make it work so if you're ready let's let's get started hello everyone who is joining us live uh let me also pop up the chat so that I can see your messages let's put it here let me know where are you joining us from and uh let me know if you are actually following this tutorial yourself hello Vladimir hello Julio Rodrigo how are you doing jish Navin and roio roio how are you doing yes we're going to have a let's get started and uh let me actually go here um and this is going to be the initial repository that you're going to get from the source code and it contains everything that we have done in part one I didn't do anything behind the scenes because I really wanted to show you step by step everything that we are doing so after you get this uh repository either from GitHub or from asset bundle uh let me actually go ahead and stop everything clear go ahead and install the node packages by running npm install this will check the package that jasonn will install uh all the dependencies in the node modules directory uh the next step is going to be to uh deploy our API for that uh we're going to have to update a couple of API keys because the ones that we have right now in the repository uh will be deleted of course not to be overused so open the API folder and let's see what will we need to change the first step is in the steps and config file here is the end point of your uh project there is something wrong with my stream now the connection seems to be excellent let me know if everything is fine from a technical perspective if you can see everything Vladimir is asking how do you still work out in the morning great question actually I just got back to the gym yesterday so yeah I had a quite a long period of uh of uh of vacation and now I'm excited to to get back to it and uh all the muscles are are sore today uh yeah not sure if everything is fine with uh the streaming software it tells me that it's not very smooth but hopefully everything is going to be okay so uh anyway back to our API in the previous um uh live stream we have deployed our we have created and deployed our stepen endpoint or our stepen API the stepen endpoint will have a name so here in the endpoints go ahead in your account check the endpoint name for example in my case I'm working with API uh soft man go ahead and change it here in order four steps then to know to which uh project to to connect to that's going to be the first step then let's check the other parts in index we don't have to do anything and I'm going to start with exercise folder exercises folder is the API is the steps and configuration that connects with API ninjas there you also need an API key so go ahead in your account on API ninjas uh press on this button show API key copy it come back here and under exercises index. graphql here in the headers you're going to see the value of your API key so replace it with your actual API key um at this point we can go ahead and start uh our graphql endpoint or let's say redeploy it um so for that I'm going to open a new terminal and here what I'm going to do is I'm going to Simply run steps and start this will look through the configuration and will redeploy uh if there are any updates the API to step in in fact our API is always running so even before running steps and start it was running because it's running in the cloud on stabs and platform now we simply said like hey check if there updates uh and redeploy it and every time we're going to do actually some updates for example if we're going to change something and save you're going to see that stabs and will redeploy this I'm going to go back and um then let's go ahead and open the dashboard here you're in the console you're going to see the URL for the dashboard steps then let's go ahead and copy this uh URL let's open it in our browser and here we're going to see some uh queries the set query might not work yet because we didn't update the mongodb API but I want to just make sure that at least our exercise API key is working so let's press on the Builder and here I'm going to close the sets and I'm going to open exercises query let me simply query the name and and let's run this query all right we see some data that means that our API that means that uh if we go here the connection from API ninja to our graphql API built with IBM staben is still working correctly if that's true let's follow along and also make sure that our connection from mongodb to graphql API is still working and then we're going to have everything ready to start implementing the feature for today for mongodb if you remember uh we used the mongodb atlas which is a way to easily host your mongodb databases in the cloud um so here we have our project go ahead log in in your account and if we go to let's say overview I'm going to go to database let's select the cluster that you are using after selecting the cluster we are going to select collections to see the list of let's say databases that we have in our uh deployment here is the sampl sample but below it we have a workhouse database that we created previous time in the workhouse database we have a collection called sets which you can think of as a table it's not a table it's called a collection because mongodb is a nosql databases and now we are adding here documents or unstructured data um so yeah we see already some exercises that we have added previously uh and every exercise contains every set contains the exercise the number of repetitions and the weight all right we also in previous live stream enable with data API so if I go to data API we should have a URL endpoint let's go ahead and copy this URL endpoint and go to our project there are two folders corl and corl 0.1 the first one which we're going to rename in a moment let's not do that now but let's open curl index graphql and this is the configuration for our graphql endpoint that will uh connect with our mongodb data database and we'll read the sets from the database so in this we have an endpoint so make sure that it's the same endpoint that you see in your data uh page here so simply copy it come back and do a search it should start with this endpoint and at the end it should have action find because we are trying to send a find request to our collection the next the the next step to make sure that this is working is to uh go ahead in the users and make sure that you have a API key here if you don't have any API API Keys uh go ahead and create an API key give it a name for example test generate copy this API key come back and replace it in the API key of our curl index graphql for the query sets go ahead replace it here save and also let's do the same thing for this second folder which is is going to be responsible for creating a new um a new set and inserting it in the database go ahead and make sure to update the API key here and double check the end point to match the one that you have and at the end we should have action do insert one after you do that open the terminal and make sure there are no errors deploying the API because if you have done like I don't know some uh error uh some typos you going to see the error here and the graphql API is not going to be deployed so if you see that deploying and then done in 2.4 seconds then we are sure that the API that we updated here the configuration of stepen has been taken into consideration and redeployed on our stepen dashboard so we can go here we can press refresh to make sure that we refresh the the schema and what we can do is we can open the next uh query called sets in the documents let's select the ID exercise reps and weight if I'm going to execute this query we should see a list of documents and they if you look they match the ones that we saw when we were exploring our database collection in the cluster one here collection yeah uh yeah in the workout sets another another things that uh might lead to some errors are the name of our cluster the name of our database and the name of our uh collection so in our in the first Coral request that is responsible for receive for reading and returning our sets or let's say finding them here we are uh specifying The Collection data source and database in your case if you name them differently maybe in your case it's not going to be cluster one but maybe it's going to be cluster zero make sure that this cluster one matches your cluster name make sure that the collection sets matches the name of your collection here for example sets and workouts this is the database so double check that uh after you deploy this is going to uh should connect to mongodb API and it should work I don't know another thing that might uh cause some issues is if you go to database data API make sure that the data API access is read and right because by default it's going to be no access and you're not going to be able to access your data so select read and write and test again all right so at this moment what do we know at this moment we know that our API uh works correctly uh so the the back end backend configuration from graphql API that we created using IPM stabs then it's connecting correctly to the API ninjas to get a list of exercises and at the same time it's correct connecting correctly to mongodb to read the list of sets from the database so let's go ahead and uh run our application R native application that we that we connected with our graph API and let's see if everything is working in the application um as we left it previous time so what I'm going to do in the first terminal or in a new terminal go ahead and do npm start this will serve a development server and we can press from here I to open an iOS simulator or we can scan this QR code using the xoo application on your device did you change the stream time no actually this is our usual time uh but today is Tuesday so we are doing more streams this week actually for the next three weeks we're going to have two streams every week a lot of ideas a lot of content that we planned for for you guys so yeah if you're interested and if you're on your journey to become a r native developer uh make sure to subscribe to our channel uh because we have a lot of tutorials project build very Hands-On tutorials for building mobile application full Stack mobile applications we very very close to reaching that Milestone of 100K and receiving the button so if you can spend fre 4 seconds to press the Subscribe button that would mean a lot to us thank you very much and let's continue with a project here we have our application running uh the home screen is a list of exercises at the moment it doesn't have like pagination so we only see the first probably 10 exercises we can press on them we go to the details page and here we see first of all more information and instructions about them exercise all of this if you remember is coming from API Ninjas for the that is providing us with the exercises data set and here we also see a list of uh sets that are in our database at the moment these are all the sets in the database so probably we're going to have to filter them by the exercise name and also by the user ID uh but before we do that what we actually have to do is go ahead and make sure that we are able to add things here at the moment adding is not implemented and this was the last feature that we stopped at during the previous live stream and this is going to be the first thing that we are going to do now so if you're ready we can we can get started let's go ahead and um what we're going to do so in the previous live stream we already started this integration for creating and save inserting sets in our mongodb database for that we have this corl 0.1 uh folder that uh is going to use the rest directive in order to send a rest uh API request to the following endpoint which is our mongodb data endpoint and if you see at the end we have action insert one meaning that this endpoint is going to help us insert um a set before we actually move along let me show you a simple Coral request that will demonstrate how adding um a set through the rest API is working if we're going to open this raw Coral examples here I have a couple of examples maybe some hies that um hopefully I'm not going to forget to delete and the last one this is the one that ends with insert one so that basically means that uh what I'm going to do is actually I'm going to leave out steps and import for a second just to send a coral request Coral is a simple utility that helps us send get an post request or any kind of request to an endpoint in this case we are sending a post request with this API key uh and the content type make sure this is your API key in order for it to work for the data source we are targeting cluster one database base workouts collection sets and we are trying to insert this document that has parameter exercise weight reps if I'm going to do here something like uh are you working question mark just for us to see if this request is working let's try to copy this Cal request open a terminal a brand new terminal and paste this C request oh my God here here it is I'm going to press enter we see inserted ID which means that something happened if I'm going to go back to our database cluster one Collections and here under workout sets we should see the the last item to have a exercise name something like are you working yes weight four reps one that means that by sending a requ a post request to the to this endpoint with this data we are actually inserting things or items in our database so that's exactly what we are doing here with our uh graphql with staben we are we are creating a graphql endpoint that will when executed will send this post request to this endpoint with the following values name Val name um and the following variables collection data source database and document exactly the ones that we have here in the data in the data collection database data source and document if I'm going to try to to insert one from stepen for example to do that I'm going going to delete this query from here let's add a new mutation in the Builder in the Builder let's add a new mutation a query in graphql is used to get data a mutation is used to create or update data so let's press on the plus sign here it's called my query for now for the collection uh for the collection database and data source what do we have for us collection is in queries if I'm going to look collection is set so let's copy paste it to make sure that we don't make mistakes database from our call request that we made sure that it's working the database is work out and the data source is cluster one but what's up with this document like how can we write something here as we see graphql at this moment thinks that this document should be a string if we look in our queries we know that our document should be an object because our document that we want to insert is an object so if we are simply going to replace it here like this and then if we're going to get back with inserted item id we're going to see that we cannot execute this because it's unexpected name and string and so on why because the document in our index graphql the variable document is of type input document the input document is a simple scalar scalar which does not specify that hey this should be an object with this kind of inputs let's rename it from scholar to input input input document and let's here provide the parameters of this input document what do does it have what do we have exercise weight and Reps so exercise should be a string and we add exclamation mark to mark it as required the exercise should be a required string then we have set not SS but reps right this is a integer so it's going to be an integer also with exclamation mark and then we have weight which is float but maybe it's not with exclamation Mar because there are some exercises that you can do uh without any added weight so now if I'm going to check the where the console to see if staben deployed it correctly it did now we can go to the dashboard and we can refresh it deleted everything that's not very nice but we can add a new mutation my query again collect what do we have here I'm going to have to remember we're going to optimize this in a moment not to have to to specify everything for example data source is this one data source collection I think it sets and databases work out and for the document already here we see that the document has reps exercise and that's it because these are the only two important the require ired one and let's for the exercise name say from stepen maybe for the weight we can specify here I don't know 45.5 you can add these variables from the user interface or directly in the query here so you saw that I added the weight directly in the query and it was automatically synchronized with a user interface in the Builder that probably you cannot see correctly because I'm hiding that view but yeah it's not that uh that important just make sure that you query back the inserted ID and with this query let's try to run it so if I execute the query we see we should see the inserted ID of the new exercise if we go to the mongodb and if we press on the refresh button at the top we should see that we already have eight documents in our d database and one of the last ones should be from steps and with the values that we specified here reps exercise and so on well that means that now from our steps then we can send a mutation and create something in our database not only read things from the database but also create them I want to go back to our uh steps and declaration and and I want to uh hard code these three Fields The Collection the data source and the database in order for us not to have to to to specify them always because I will also rename the the my query to insert insert set the the mutation which in fact is a mutation is going to be insert set then I'm also going to rename this input to set uh let's say new set let's copy this name and replace it here under the document from input document to new set now uh I will take this threee and I will move them here after the headers as uh body how is it called I'm going to look in the previous example let's open the previous scroll folder and here we have the post body the post body that hard codes The Collection data source and database let's do the same for our headers we actually don't need a comma we just put the post body um string with some with triple codes and here we specify collection data source and database now that we have hardcoded them in the post body here we can safely remove them from our variables not to ask them from the user or from yeah from our front end now if we save and if I check everything to be deployed without errors can go back to to here let me select all and copy my mutation because after I press refresh most probably is going to yeah reset to set and I can go back and set it here to this one one right away we see that there is no mutation called my query because now it's called insert set and the insert set doesn't need all these collection data source and database because we have hardcoded them and we it only needs the document for the Reps and so on that's nice um The Next Step while we are here for for us to be able to send this request from our user interface we should not hardcode the values of WS exercise and so on here but rather add it on the mutation I'm going to rename this mutation to insert set and I'm going to add here a variable the variable is going to be uh dollar sign new set and the type type should be new set and it should be no like this this new set type is coming from the input that we specified here so now I can remove the do from the document I can remove everything here or maybe not remove but let's copy it we're going to need it in a moment let's just simply put the variable new set here and in the variables we're going to need that uh that object but here it's Json so we need to um wrap our keys in a string as well for the weight let's do it like this and what's happening yeah actually uh we need to have a object with a value new set that is an object so at the end I'm going to have to close another object I hope it's or maybe I can do prettify yes so now from variables we can send this information I can send it and we see Condon generate a remote URL specification okay that's interesting something is wrong there why did we mess up here collection sets data source cluster one database document new set insert set insert set document exercise should be a string WPS should be in weight should be float specification on the URL puff insert set if I'm going to take this object and hardcode it back here I just want to try to understand if it's if a problem is with the object or if a problem is with something else that we have created so let me just do it like this no it's still it's still an error document uh what did I do wrong here insert set document new set post body here we also have this post body H interesting interesting let me see how many more parts are you making for this application I think this is going to be the last one Julio let me try to get back to your question a bit later uh the end point post body I'm looking at the previous one it had this request headers is this might be the error I don't think so let's do copy refresh and run again no it doesn't want headers variables pretty sure it should be with this post body because if I comment it out and then add back this collection string data source uh string and database string and then if I go here uh refresh and basically going back so for for the collection it's going to be set database workouts and data source cluster one let's see yeah now it works why the same way of post buies working in our sets request let me see if it actually works I'm going to copy this mutation and I'm going to try uh a set query yeah it's working with how specifying but at the same time we don't have any variables so maybe it's not correctly uh merging them together you know yeah I think so because if I go back to this mutation and if I for example yeah I think here I need to add um if we specify post body then our variables where not here not here in the previous one if we have a post body here then our variables are going to be completely ignored so that means that uh if I run connection yes so that means that here I'm going to have to say that that document document should come from a variable but how to access variable let's check the steps and documentation stepen post by body the message body for the request variables are supported C directive reference perfect uh so here let's search for post body where is it here post body yeah the step Zen will automatically generate this post body based on the variables but if we provideed uh yeah it's oh it's V syntax uh consider pay bar okay so first name and last name to access them we are using this syntax so let me copy it in our in the document we need to provide here get the parameter name is called called document and we will remove a collection database and data source uh so now we are overriding or not we are specifying the post body where we hard code The Collection data source and database to make it easier for us to send this request not to have to specify them all the time and for the document we are simply accessing where we are getting it from our variables here so let's see if we don't have have any errors we don't let's go to our dashboard Let's uh copy refresh remove a collection database because we remove them run the query and again it's not working it's not working again document get document new set maybe we cannot get the whole document maybe we're going to have to do them separately with name with exercise reps and weight let's see the documentation if they specify anything about object first name last name batch without oppos body to pass Jason as argument in the graph mutation the argument Json patch must be added as a variable to the post body argument Jason patch but that's a string oh get Jason get Jason but in our case that's not a Jason so I think you know what we're going to do we're going to Simply say that that do document how can we create a object here can we do it like this just simply overwriting them like exercise test uh reps 10 and weight 10 will this work send or refresh and then send sets cluster workouts maybe have a type of somewhere that you can see set cluster workout okay so there seems to be some issues with this one maybe I don't um I miss something where I have a typo but I don't see at the moment uh so I was expecting it to work like this but we're going to work with what we have document document we're going to work with by commenting this out and by having that collection as a string here collection as a string uh can we maybe hardcode it here no no no we cannot collection string um we are going to have a data source uh string and database also string so now at least it's working so we can move on I'm going to refresh and the only thing is that we're going to have to we're going to have to specify this fields and of course they will be required so I'm going to put them as required all of them refresh refresh refresh and we see that we need more more things here for example the maybe we don't need it here yeah as we can see the new set here because we made it required in the mutation should also be required and in the insert set we also need to specify here database which we are going to to hard code in the query uh document itself so it's going to be workout uh I'm going to do data source it's going to be cluster one and for the collection for the collection we're going to have set now the variables will still be only the new set and if we execute should work yes we see inserted and from steps Zen one to three if I executed let's copy the inserted ID and let's check in the mongodb if by filtering here and we're going to look for ID object ID and this one you can scroll and find it but I'm going to look for it yes we see from steps in one two three reps and weight is coming directly from our variables okay perfect let's go ahead and copy the document of this mutation because we need to execute the same mutation in our rec native application when we press add button so we're going to need that in our source let's see where we have it in the components we have new set input let's start by writing the const um mutation document equal we need have a graphql so let's import graphql from where did we import the graphql from from graphql request from graph request so let's define this query and and let's paste it the one that we copied from our dashboard and that we tested that it's working correctly after we have done that we will need to execute this mutation but for that we're going to need the to import the hook use mutation from T rect query and also the what and the graphql client we are going to also need the graphql client from the one that we have defined with configuration on how to connect with our steps then it's in this file graphql client simply adds the authorization with API key in this API key make sure that in the environment you have your own API key from stepen now let's go ahead in our new set input component here let's define the uh the use mutation hook in Vis mutation we need to send some an object with what let me open the documentation of use mutation from react query we are using the latest version with version five and let's go to the documentation from here let's check uh where mutation mutations we just need the mutation function mutation function which is an aing function that will receive some data for example uh new set and what it will do is it will use the graphql client uh it will RoR graph qu client Dot request the request that we're going to do is this mutation document and the variables let me see let me see how we did it previously graphical client. request and also we need to send some variables so here variables no yes the variables are going to be the new set that we are going to receive here when executing the mutation but how do we execute the mutation well the Ed mutation hook will not execute the mutation it will it will only set it up and it will give us back uh the mutate function that when called uh with a new set will execute this mutation function so we need to call that in the on ADD set and here let's do that by calling mutate and we need to send the variables that will be the new set for example exercise is going to be from up reps uh is going to be 10 let's just try test it out to to make sure that it's working and weight is going to be 10 as well not sure what what it says but uh but we can try to press it here and look for from application document but exercise in our database of sets so let's reset it here the filter let's refresh and we have 12 if I look at the last one I hope to see from up we have 12 maybe are more pages if I'm going to press one more time and go ahead and refresh will we have 13 no that means that there is an error the error handling in a mutation uh can happen in a couple of ways mutation here mutation do is error so here the use motation will give us back also the error and also there is error and also is pending so whenever is pending that means that we are executing the the mutation so we should wait I could uh change the title of our button to um to a conditional like if is spending question mark I'm going to do adding it's going to look weird but at least we're going to see if something is happening and after the button I'm going to have to to to put another view because after the whole row that we currently have in the new set I want to to let's put a new view I want to write here a text where we will say some error failed to add the the set and in order for this Tex to be inside the container let's move the styles from here to the top view and the styles that we're going to have to this view are only going to be styles. row raw not raw row like this so let's go in the style shed and the container will not have Flex Direction row that's the difference only the row style will have Flex Direction row and the Gap also from here we're going to move it here maybe there as well because we need some gap between the lines for the text you can add some style like color red and we are going to conditionally render it only if there is an error only if is error is true so let's check here if is error only when render the text by doing it like this so I'm going to try to press add fail to add set but why we can go ahead and maybe better to Simply console log the error to see what's happening there if I press let's open the console where we have our metro running so if I press add here we see new set of required type new set was not provided new set of provided new set new set variables variables should be an object where we have a key new set okay that was probably the error now if I'm going to do add uh again was not provided variables set notation function new set let me try to Simply override them here directly like new set is equal to this one and see if it's going to work no it's still not working graphql request and I need variables let's check graph C well request to see how maybe I'm missing something for the the mutation itself all right here let's see I need a request I need a mutation mutation add movie title variables and graph call request mutation and then variables so it's not an object with a key variables is directly the variables that's my mistake it's not an object with variables but is directly the the variables object so like this wait wait wait wait wait wait um I need to remove variables this one I need to remove this and last one now it should be just an object inside that we have a new set which if I'm going to press add it worked now I'm going to move from hardcoded to a variable that we're going to receive from m and because we have a same name I can simplify it like this even like this and because we have like one return statement I can remove a return and I can remove this Branch brackets in order for uh the arrow function to return automatically the response from graph client so now our this use mutation is much simpler we have a mutation function it will receive a new set it will send it here and if I do here add a data that we have here should go in our database and now instead of 12 if I refresh we should have 14 yes because we press it two times but instead of hardcoding the Reps and weight we need to take them from the values that the user writes here to do that the Reps we're going to take from the state variable reps the problem is that they are still um a string so what I'm going to do is I'm going to say number pars int and we're going to send the Reps string from the State variable this way we are transforming from a string to a number and the same thing with a weight but in this case it's going to be number. pars float weight okay so if I'm going to do for WPS one two three and for weight 10 and if I'm going to press add let's see what was added in that database so I'm going to refresh I'm going to scroll down until we find that from the application reps 1 2 3 weight 10 perfect and the same thing like if I do reps five and weight 7.5 will it correctly parse the 0.5 let's check that out I'm going to refresh again 7.5 in the weight perfect so cheers for that let's drink some coffee and we're going to continue um we also need the exercise because at the moment we're hardcoding it right where we will take it from well in this new set input we don't have we don't know the exercise but on the page where we use the new set input which is our uh source application and the name The Details page in this page we actually know the exercise name because we actually know the exercise so what I'm going to do is let's to the new set input let's send here the exercise name or maybe the whole exercise or only the name let's only choose the exercise. name now we are sending through uh through properties with the name of exercise to the new set input let's go to the new set input and receive it with the same property name exercise name now we can take it and instead of hard coding from the app let's use exercise name so now we are in for example T Bar row with handle if I'm going to do 15 wraps with no weight let's see what how it will work in this situation uh let's check in the database refresh 17 documents the last one is the exercise T Bar row with handle 15 reps and the weight is null perfect that's okay because we didn't specify weight this is a let's say um an exercise without any weights okay perfect so now we have finished like the full cycle of connecting uh our user interface and when the user inputs something here we are going to send it to our graphql API our graphql API will save it in our mongodb database and then later one if we we come back there to that exercise we're going to be able to query it and see the repetitions in this list let's wait to see them loading something happened there cannot read property sets of undefined I think we broke it with this null value H you know why because we specify that weight in our graph ql end point if we look at the API Cal folder when requesting it we specify that the weight should be a float but not a null H is that the reason why it's fa fa failing because if I update let's let's see if for example uh querying with sets from dashboard works it doesn't if we change this to how to update it to I think it would be better if we don't save it at all if it's not there so that would happen from our new set input here let's do const new set equal to this value but we don't put the weight in the new set we actually check if something exist then new set new set. weight is equal to number parse float so maybe we can check if number parse float yeah if it's an an actual number then we only when we add it um in our new set object because this is optional and sometimes it's not going to be so instead of writing n v here we are going to not put it at all now this new set we're going to have to send to the new to the mutate function and I'm actually going to go ahead and remove how do I remove this one remove this one with null weight and try again to see how it works let's go here let's say that we did 10 repetitions of this one and let's add the set let's go here let's refresh T Bar row reps and it doesn't have any weight but if I'm going to add a rep still doesn't work weird uh but if I'm going to add one and two adding will it add then just testing like the edge cases you know like having the weight not having a weight yes it works here as well but anyway like the set request is still not working that's a bit weird uh y set document let me check in the coral index here what do we have documents entry documents ID exercise if I only have a ID here still doesn't work did I mess something here with both body maybe it doesn't need the last comma yeah you know what maybe maybe I fix that issue that I had before maybe I simply had that comma in the other graphql no I didn't I don't know but now if I go to the tar row handle for example we see this list perfect so uh we have successfully saved new sets in the database from the application all the way from our application to graphql from graphql to our mongod DB the next step is going to be to probably first of all filter uh when we uh request the sets to filter them by the exercise because if I go to any exercise it's going to contain the same list so that's going to be the next step but before that let me go ahead and do a git uh git checkout main get add get commit save sets to database and get push origin main all right how are you doing guys following along everything nice everything working for you hello asish hello I think Rohan for uh Julio is asking about the responsiveness how to to work with it uh yeah there are a lot of ways but in a lot of cases you would the rule of um is to work with mostly Flex boxes so instead of uh specifying fixed with that works nice on a one screen size you rather work with flex boxes and relative whips uh maybe uh if you also want to deploy it on large screen sizes think about Max whips as well not only like if an item is 100% of a screen on the phone it might be okay but on a a tablet or an web you might want to have it uh to have it as a maximum wi not to be stretched the whole uh wi of a screen then again yes like you work with Dimensions to have some some rules around for example it depends on the layout that you're are building but if you have a list and you want on the mobile to have one single column but on tablets to have two columns and on web to have three columns the amount of columns you you can calculate based on the dimension so take the dimension check like the the dimension um ranges and make like the the number of columns uh variable based on that so that that that would be how how it works or you can use some libraries for example uh you can use um tamagi which is great for for this responsiveness but again you don't necessarily have to use anything extra you can do it yourself without any additional dependencies some cases it's just easier to use like a library that is created for that anyway let's continue let's continue building our application uh we're going to start fixing some stuff for example if I go to our detail screen we have an error saying that virtualized list should never be nested inside plain scroll view with the same orientation why is this happening well this is happening because our sets list is actually a flat list a flat list that we can scroll through uh and if we look where we use this set list sets list we are going to see that we are using that in our application in the name in the in the detail screen in this is where we render the sets list again set list is a a flat list and it's used inside a scroll View view the whole page is scrollable the flat list is scrollable and uh it's not recommended to have two scrollable things with the same direction nested one inside another because yeah like when we scroll like we don't know like what which exact which list we actually want to scroll you might think that we can simply transform this scroll View to a view uh this one to a style and it will work as we expect but no actually it's not going to work because everything at the top that we have here will remain static and only the thing that we have here will be scrollable so if for example we leave it even less space only this part is going to be scrollable some cases maybe that's what you want but sometimes you want to scroll the whole page right to do that there is a way to to actually implement it and the way to do it is to send to the flat list a property called list uh header component so if you send here some GSX for example a text header with style font size 20 in that case the component is going to scroll together with the items so as you can see the header is there but it Scrolls together with the items now the thing is that the flat list is in our sets list but everything else on the top is in the parent component so how do we manage everything well it's going to be a bit uh interesting but we're going to Simply send it through parameters to this set list also as a let's call it again list header component this is going to be equal to let's say the same text header that we that we are currently displaying so let me copy it from here and send it through parameters Now list header component we are sending it to the sets list let's go to the sets list and let's receive it here in the properties it's called list header component now let's simply take it and pass it down to our flat list now what does that mean that means that our sets list is responsible for rendering the sets but is not responsible for rendering the header it only receives it and pass it down to the flat list we still have this header at the top but it's managed from the parrent component so from the parent we can changing from outside so if I save we see changing from outside what does that mean that means that instead of rendering a text here we can render everything else above the sets list uh maybe this Tex screen I'm going to leave there but the panel the second panel with instructions and so one we're going to copy from V and we're going to put it here and because every component should the component should be like one single component we're going to wrap it around a uh empty brackets which is also called template string so if we do that now we should have this container that is scrollable and it doesn't compl compl that it has a list inside the list perfect yes we lost some Styles because now if you remember the in the container which is now the page we had this Gap now it's not no longer working here so I'm going to remove a gap from from the container and we will have to add it to the parent component here at the moment there is nothing here so what I'm going to do is I'm going to do a view U uh with a style Gap five or how much it was now the styles are back here okay so yeah it's a bit weird but uh if you understand like how everything moves around uh it actually makes sense you can optimize this by extracting the whole header into a separate component passing there like variables uh but that's going to be a bit time consuming but it's going to make your code cleaner because right now the sets list is opening here and it's ending all the way here so it's quite a long component where we have simply one huge property that specify how it should WR the header this one let's see if it still works yes if it still works we can add adding it's adding perfect um the a scroll bar here we can either hide it and probably to hide it we're going to go to the flat list in the sets list and say show hor not horizontal but vertical scroll indicator false and in this case we do not see the the scroll indicator there okay okay all right so that was a little bit of cleaning yeah all right let me do get add get commit refactor Le uh Details page to not have nested lists all right the next step The Next Step I think is going to be uh filtering out all and displaying only the sets that are related to this exact um exercise to do that what we have to implement is let's see at the raw Coral example and the first Coral request here is the one that finds exercises at the moment if I copy everything except the steps then import and if I send it in our terminal uh we're going to see that it actually returns basically everything we will need to somehow pass through the data a variable that will specify the filtering that we want to apply when reading items from the database let's go ahead and our mongodb in the data API open the documentation to see how we can send this filter uh where is it Advanced view our API documentation here it should be the data API uh the document that API examples let's find find a single document this is find one find multiple documents this is the action fine that we are looking at and here we see that we specify all the data sour database collection and also the filter so the filter that we're going to use first of all Let's test it on our actual database because we can go to the database through the atlas and test the filter that we would like to use for example I will open the sets and I will scroll down and I will only want to check the exercises for this T Bar row with handle in the filter we can specify an object where we want to specify yeah basically the filter so we will say that we only want the exercise or I think it's exercise like this where it matches this T Bar row with handle if I'm going to apply the query will only return me one item that matches that not one one but all the items where the exercise matches this one so that means that we can use this one this filter object as it's shown in the documentation in that data of our request so let's go here where we have our C request where we have data raw let's do comma at the end and add filter and let's paste the filter that we got there will it work not sure filter object object H maybe it will I hope it will so let's copy this cor request again open the terminal and now if I will execute it I expect it to return only one item item invalid syntax of course uh why filter exercise inv character this one after object key oh oh oh I see I see I see I made the typo I put the filter closing brackets yeah not in the right place now if I'm going to execute it again we should see only one document all right that's good now what that means is that we can add a filter parameter to our steps and uh endpoint and the end point to request sets is in our qu folder and remember the first step that I'm going to do is actually rename this from curl to uh let's rename it to mongodb mongodb and after renaming the folder we need to go into the API index and here instead of curl say mongod DB now let's go into the mongodb and what do we have here we have a post body and again we're going to have to add a new variable to this uh query and probably it's not going to work by appending it here but let's try uh well I'm going to do it a bit differently let me try to do it directly here by specifying filter and by specifying an object where where the xer size is going to be equal to how did we have it there this one let me see if it was deployed correctly I think it was and let's see through a dashboard by simply sending a request to the sets if it's yes it works in this situation that means that I can add a variable to our sets query called exercise of type string and here we need to get that variable to get the variable back in our graphql directive we will see that how to get it get Json or get simply do getet here so instead of T Bar handle I'm going to leave a string and I'm only going to add the do getet exercise will it work it doesn't need the dollar sign that's in a different part there is simply exercise will it work it was deployed let's see in our dashboard if I refresh we're going to try unable to find key exercise because the key exercise should be required if we are trying to get it and if I refresh now we see that we need to provide here the exercise that is going to be a variable exercise of type with dollar sign of type string required now in the variables field here let's specify exercise and let's get the name where is it T Bar something if I execute yes uh let me close the history we have the only the documents or only the sets for this T Bar row if I'm going to check another exercise that we have in our here for example push from from here if I'm going to say only give me exercise push yes it works and it actually returns from only the push exercises that means that we updated our query let's copy it and let's go in our in our R native application right now it's not going to work because we updated the query itself we need to go to the source application name because not name in the components sets list in the sets list we have a query let's remove it and update it to have a variable exercise here as well sets list uh sets list because our query has a variable we have to add to our query key as well because all the queries for different exercises they will be different but again we need to know them the name of the exercise here we don't know it but in the detail screen we know it in a similar way how we sent the exercise name to the new set input let's send it to our sets list as well because we need the exercise name in the list to be able to only query exercises with this exercise name again in order for react query to Cache with data for different exercise queries differently uh separately and not override previous ones we will have to add after sets another variable that indicates like the variable to which we want to identify this query with so in this case it's going to be exercise name the exercise name will also go into the variables here so the variables is an object with with have a value exercise exercise with a key exercise and the value the exercise name that we receive all right now if everything is working if we go here we see only one set if we go to the T Bar row with handle we see only one set and if we go to for example something else we see no sets yeah for Atlas Stone we see no sets nice perfect so uh now if I'm going to add like for example four and three here to Atlas Stone it doesn't refresh automatically uh but if I go back and come here we see that it was actually added correctly in queried correctly uh the next question is how can we automatically update our UI after we send this mutation uh that's going to be the next step let me go ahead and Commit This one git add git commit minus M um filter sets based on exercise get push origin main yeah the question is uh how can we update it automatically and not having to go back and come here to update it uh that's where in the sets list we specify the key of this query and by targeting this key we can when executing the mutation we can say hey go ahead and revalidate this query that has the key sets and with this exercise name so in the new set input uh here uh let's look in the documentation to double check in the mutation here how to do that invalidate queries even with just variables mutations aren't all that special but when used with on success option the query client invalidate queries method and the query clients set query data mutation can be very powerful tool okay motation let's see if um yeah we we can pass we can specify a on success method in the mutation and this function is going to be uh called when uh the mutation successfully executes so in the new set input below the mutation function let's say on success this is a function that can give you the data for example dat variables and context that was used but it will simply for now we can only we can do a console warrant hooray so if I'm going to go here and add something we see a heray method I'm going to remove a previous ad set console log which means that we can do something when the mutation successfully executes what we need to do is we need to invalidate another query that will update our list of sets to do that let's see let's see how to invalidate probably it's not going to be here no don't think it's going to be here but it's going to be invalidation from ation or yeah invalidating query is only half of a battle knowing when to invalidate them is the other half usually when a mutation in your up suceeds it's very likely that there are related queries in your application that needs to be invalidated so in our case when we add a set to a specific exercise we need to invalidate the sets list the query that is displaying the list of sets for that exercise and only for that exercise not all the queries in our application that starts with sets for other exercises right so yeah let's see we need the query client and we get the query client uh using a use Query client Hook from react query use Query client let's take it well it's not here it's in the new set input in the new set input besides the use mutation we are also going to import the use Query client let's get access to this query client query client equal use Query client and on success we can use the query client do invalidate queries and here we need to say what queries do we want to invalidate here we need to specify a query key let's pass here an object query key and the query key this is where actually query keys are also helpful if we simply say invalidate the query key set and if I'm going to refresh going here to and four add it automatically refreshes because we don't necessarily have to provide the full key we can provide only the beginning of a key and it will work so in this case we are invalidating all the queries where the query key has the first element sets the problem is that if we leave it like this yes it works here but it's not going to be very performant because it will invalidate the queries of all the exercises the thing is that we know that by adding um repetition here but by adding a set here we only want to update the the query that is responsible for this page so by adding here the second variable which matches our variable in the the query the exercise name exercise name we are making sure that we only validate the query that is on that is responsible for this exercise so here yeah It's Tricky as they said like one way is to invalidate but another way is to know when to invalidate in which exactly queries so if I go here for example to the first one I can add to four add it's adding and uh two and four is here another thing what I can do is uh instead of resetting the fields when we execute the motate I would rather reset them when we have a success on success because now if I do it five and six add it's adding and only then they are reset I think this way it's it's much better and they automatically update and appear here below okay so that was our query invalidation and uh having like synchronization of different queries and mutations get add get commit uh invalidate sets query when adding a new set get push origin main perfect okay so so far so good um The Next Step I think is going to be to link sets to the user because right now if we look in our database looking at a set we don't know which user in our application perform that set this is fine if you're building this application only for yourself and if you have only one user in your application probably in a most situation you're going to have multiple users in the in the application and you need need to somehow link the data to to a specific user or to a specific device to do that we would have to implement some authentication system if we want to link to a specific user and if we want to allow him to sign in from different devices but we are not going to do that what we are going to do is we are going to link data to a specific device this way the user doesn't have to sign up he will download the application he will start start using it right away and we're going to link the data to a device ID and whenever he will use that device to sign in we will be able to retrieve only his data this is going to be much easier to to implement uh and the same time I'll set the base for this userbase um data hey Bai how are you doing Bai is are you from Barcelona could I use graphql API server separately and how what do you mean separately yes like graph qu API server is an independent piece so it doesn't have to be part of re native or anything else like rea native is the front end and the back end is graphql and they are completely independent of one another uh for Simplicity I created this API in our folder but it doesn't have to be here it's nowhere linked so it can be in a separate folder as well so yeah they are independent separate and you can connect different clients for example if you have a website you can connect to the same API to the same graphql API all right guys give me uh one minute uh I'm going to go grab another coffee I'm going to come back and we're going to continue with uh linking sets or linking data to specific users or let's say specific devices in our application then we're going to have charts searching filtering pagination okay a lot of things to do still so but we're going to learn a lot today see you in a second for hey guys I'm back okay so got the coffee uh got some pistachos to to f fuel for for it and we are ready to continue uh o very interesting question um to this comment can we track how much calories burn while doing an exercise uh by using an API or methods uh that's a good question and to be honest uh we could uh with everything is possible that's my answer um there is a for formula for exercise calorie calorie uh formula um yeah there is this m the way to determine how much how much calories uh you you are burning so the formula depends on this Ms and depending on the uh time that you perform the exercise so for example cycling at V speed uses around four Ms and when you put this value in a formula where is the formula here how to calculate Ms to determine calories the calories expanded by activity we use this formula m is multiply by 3.5 then then multiply by the body weight of a person divided by 200 and that's going to be the calories per minute and then you multiply that by the minutes that the person is doing the exercise and you're going to see how many calories in total he did so an example of this calculation is here for example uh 30 years old man 77 kg performing 45 minutes of running at 7 uh miles per hour uh based on the mat uh of this exercise that we can see here in the table we calculated that we are this person with this uh body weight is uh burning 15 calories uh a minute and in 45 minutes that's going to be 700 calories so yeah uh you would need to have a database of different exercises and for every exercise we are Ms you can have like some me's database you can find information here for example with a quick search here I found the ultimate Matt database am I looking at the right no I think no not at the right thing uh but what does m m stand for so yeah that's possible metabolic equivalent yeah so you there are databases of this for every exercise and you can do that andr thank you very much for your comment uh is this application will work in offline mode means data synchronization at this moment no but we could do that we could do that uh by using the TCH query and where is the let's say where is it there should be a way to to make it offline first offline queries and mutations but yeah you would have to to look into the documentation and take a couple of steps to to implement simply there there is a way to to persist the query client and that's the easiest way to make it at least somehow offline first by simply persisting your uh cache of all the W queries that you have run so if you open the application you load the data and it persists it writes it to the device storage so next time when you open it without internet connection it will simply load it from State and this is super simple to implement you just add a plug-in and you just add a PL plugin like this where is it back cach busting and so on uh and it will work with mutations uh for example if you want to use the application write some sets and run the mutations when you don't have internet connection and when having the internet connection in that situation you would have to synchronize and send the mutation to the database but it's it's also possible uh let me see the last comment and then we can continue I need some energy I started uh starting by keto diet and this is the second day and I feel low energy so I'm going to snack on some uh pistachos if you don't mind I'm a graduate student I'm a beginner in Native for my college final year project I would like to create a fitness app using Calories burning features in it is it easy or not as I explained is it's not that complicated you just need a a database of Mets and by putting into this simple formula you would need you would need um a couple of variables me for me for the exercise that is the user is performing his body weight it's important and the time he's performing it the time for example you can estimate if he's doing like push-ups you can estimate based on the amount of sets if you think okay he's doing eight sets how much time does that take usually couple of seconds at set maybe 20 seconds in total over 30 seconds so by doing these averages you can you can have and calculate an an estimated number of calories burned Victor Victor became a member member for nine months thank you I'll be back later but just to say that you are the man Vadim thank you for your work and passion for the program and especially for teaching thank you very much I really appreciate your support Victor all right guys so let's get back to to working and if you're enjoying it so far make sure to subscribe to the channel it helps us a lot we're very close to the 100K subscribers and if you can do us a favor that I do appreciate it very very much uh so where are we here linking sets to the user as I said linking it to a user needs an authentication system that's out of the scope for this tutorial we have other tutorials on the channel if you're interested in uh integrating of authentication system in a in a stack that we are using here I would recommend going with clerk uh because it's an independent and it's only focusing on of indc ation but again this is out of the scope so to link sets to the user we're going to actually link the sets to a device to link it to a device we need to know an identifier of a device to know the identifier of a device there is the Expo device package that can give us a couple of information I'm actually not sure if it will give us the ID of a device it will give us a lot of information about about the device like design name and so on device name but the device ID will it give us model ID but this is model OS no this is about operating system no I don't think this is what we actually need let me put it in code okay Rec native device info the devic is unique ID known as the device ID which can be useful for certain functionalities let's see this Library re native device info and see what the status of this Library let's see if it supports Expo get unique ID let's see get device ID get the device ID no I need device unique ID but identifier is consider sensitive information yeah I know this this is a bit tricky in some app stores uh like Google Play and may lead to your app being removed or rejected if used without user consent or for an appropriate An approved purposes refer to store policies for more information this get the device unique ID on Android it is currently or maybe we can add a simple very very simple authentication form where you just do like give me your username and it will save it on the user device and it will use it for later not to have to go through this because yes like it's a bit strict around like identifier users this way and unless you specify this or make sure that the user knows it it's against the uh the the rules for Google Play and other soures so probably I'm going to add uh instead of that I'm going to add a very simple uh authentication uh form that will ask for the username and then uh hopefully it's not going to take us too much time to do that but it will ask for the username and then we're going to use that username to link um uh exercises and sets to that specific user so what do we need we first of all need um let's say a new file called off. GSX in the off. jsx let me do a react native function export to generate a blank template for hour of screen off screen should be screen off screen in the index for for a second what I'm going to do is I'm going to comment out the return with a flat list and I'm going to Simply do a a return redirect to the HRA to our newly created off screen just for us to be able to see the off screen why is it going to the exercise name it's going to the off okay now in the off uh what I need is a stack screen but but please don't waste a lot of time import stack from export router I just want to change the name here to not the name but the screen the options title um sign sign in and here I'm going to have a state variable for our username username set username use State that's going to be initially like this uh and for the text username and let's put a text input below that will have a placeholder or let's start with a value of the text input for me it was imported from react native web which is wrong it should be imported from react native text input and as I said the value is going to come from our username State the on change text again is going to be set username and the placeholder let's do here username after everything we're going to have a button imported from I'm not sure why it's imported from RE native web should import from here and this button will have a title saying uh sign in okay let's add some styles styles shed let's do const Styles equal Styles do create and we're going to have a style for the page a style for the label a style for the input and that's it the button will be the default button let's assign these styles to our view for example styles. page this one is going to be our label and this one is going to be our input the page the page page we'll do we'll have a flex one in order for it to take the full uh vertical space and this will help us align everything inside it on the center of the screen with uh align items Center um actually I want to justify content justify content this will put everything in the center for the input or let's add some pading of page ping 10 for the input I'm going to do the following border with one or let me copy the styles for the input that we have defined in the components new set input where we have some input with border and so on and it's going to simplify us a little bit of work here it has Flex one I'm going to remove move the flex one and now it looks better for the label let's add a gap on the page to add some spacing between the label button and so on for the label font weight bold font size 20 maybe font color or just color gray dark gray dim gray and not Bal by 500 500 600 something like that okay so here we have a very basic uh signin screen maybe the background color of our page should be white background color white okay now I can write here something I can press sign in and when that happens we have to call a function called on sign in this is going to be a function on sign in when we press on the button on press on sign in what should happen What should happen here [Music] is we need to store somewhere this username because we're going to need it in other parts of our application for example when querying user sets we're going to need the username for that we need let's say a global a global state where we will store the username when we press sign in here and from where we will read the username where we will need it later because in our screens we're not going to be able to access this username which is a local state variable that's why we need a context provider let's go ahead and learn how to quad that I'm going to create a new folder for providers or contexts and let's create a new one a new file here called off context dogs X GSX to define a react context provider in general a react context provider helps us um Implement easily and out of a box Global State and sh share data between components to do that we first have to uh create the context by importing the function create context from react let's go ahead and create this context uh it's going to be called off context equal create context by default it needs to be a default variable which is going to be an empty uh object the off context now has two things it has off context do provider which is a way to uh to expose variables to our uh to our components and a consumer which helps us consumer get values from our context let's go ahead and um let's go ahead and Define here a new component called off context provider which is going to be a component and this component will be the one that will uh expose or that will wrap around the off context. provider as you can see the off context. provider expects a value and this value is going to be what we expose to our components what do we want to expose to our components well it's a variable called username right ABC but to which components will this username be available to it's going to be available to all the components inside this off context provider at the moment we don't have anything here but we want actually basically all the screens in our application to have access to this one so we're going to use a specific property props prop in react called children that is going to be a way to pass down to a custom component um a react three or a list of children so by simply rendering here children the children that we are going to receive through off context provider will be rendered ins hi the context provider and we will have access to the username let's see how we should render and where we should render this off context provider and where these children will come from to do that we need to First export theault of context provider and let's go ahead and think about where do we need to put it as I said we need access to the username in most of the screens or let's say in all screens in our application that means that this is a global context provider Global context providers I mentioned previously that they should be declared and specified inside our root layout so let's open upore layout and the same way as we are rendering here the query client provider the same way we are going to render the off context provider so first let's import it from providers and then off context and let's render it probably above we'll see if it's above or below and we're going to wrap everything here inside the of context provider now remember the children that I was mentioning the children is a special prop and the children property is going to be everything that we see here so in a way when react is rendering this it's in a way like copying everything that we render here and passing to the children and pasting it here and this way all the stacks that we have here will have access to the username going to go back because it was just a way to understand for us but yeah now all the screens will have access to this off Contex provider now let's see how we can uh consume this username for example in the in the let's say in this index if I want to get access to the username and only redirect if a username is not set what I'm going to do is I need to a couple of things I need I need access to this off context we can get access to that off context through a hook called use context I'm going to export from this file a custom hook that will simplify our access to our off context it's going to be called use off it's going to be equal to a function that will call use context and we'll specify our context here export const so whenever we will use the hook use off we are actually using a context called off context let's go ahead in our index and import use of from providers of context now in our component here somewhere at the top we can say const something equal use off what we are going to receive back is the value that we specified here the value is an object it has a username so if I'm going to destructure the username from here let's do the following let's re redirect to the offscreen only if the username is not there so if username is not set we're going to redirect to the authentication screen otherwise we're going to render a home screen because the user is already authenticated so if I refresh we see the home screen and if for example I'm going to add here a text a text uh with a username we should see the username that we specify a ABC that we specified here well the thing is that initially there will be no username uh and the username is going to change so the username will become a state variable inside our off context provider set username is equal use normal react State initially it's going to be empty string let's remove hardcoded ABC and provide this username from here because it's empty string we see that we are automatically redirected here and if I will write here abcda a and I will refresh it will stay here but yeah if it's empty it redirects us automatically because in the index on the home screen we are checking if the username is not set we are redirecting to the slash off off now when we write something here and press sign in we want to update the username in the off context provider to update the username we need to call the set username and to call this set username we need to have access to it to have access to it we need to export it from this off context provider we can export uh values and we can also export functions because in JavaScript a function is a variable now that we are exposing set username let's go on the off screen and here and maybe I'm going to um let's say local and let's rename this to local username and this one to set local username uh not to confuse them because local username and let's replace it in the text input local username is the things that we are currently writing here after we press sign in only then we want to update it in the global state so that's why we have a local state here and one in the context let's get access to the use of hook that is our of context and from there let's get the set username and when we press on the button I want to call set username with a local username that the user typed into the input now if I write here for example Vadim and press sign in it's not going to redirect me anywhere but it is going to set it in the global state in order to redirect on this off screen let's also get the username from our Global from our global provider username and I'm going to do the following I'm going to check again if username in this situation is defined if it's not null in that case I want to return a redirect to our home screen HRA slash so this way initially we are redirected to the sign in on the usern name I'm going to check I'm going to write here Vadim I'm going to press sign in and I'm redirected back to the home screen and at the top we see Vadim and yeah I can go back I can come here and it's always going to be saved because it's a global State Veer if I'm going to refresh it's still going to redirect me to the sign in I'm going to say adim sign in and here we are um from the off screen that's actually the correct way of guarding this like if you are already authenticated go away like don't don't stay on the off screen but here in the index it's actually not the right moment to do this redirection because this way we are only guarding the home screen if for example someone would open the directly through a deep link the detail screen the detail screen is not guarded in any way so an unauthenticated user will be able to check it so a better way to check this and guard uh is going to be invel layout or maybe not even in layout because the layout is the root layout but it's going to be I'm I'm going to leave it like this now that's that's I'm going too deep into the authentication workflow uh which is not the goal of this tutorial we can if you want to guard the the detail screen you can add the same if statement there so it's still going to work but but because we don't use like deep Lings here we are going through the home screen everything is going to be fine so in the index I just need to remove this username uh in the offscreen the set username and username here shows with an error because yes even though we are not using typescript uh my visual studio code is trying to infirm the types and if we look in the providers the problem is that when we Define the off context provider we are setting the value username and set username but we when we create it we do not set it so in that situation we need to provide some default values for example username the default value is going to be empty string and the set user usern name is going to be a function that will do nothing and in this way on the offs screen the set username and username actually work works but the set username should expect a variable so set username here is going to be uh username of type string or just username and now and now in the off yes the red warnings disappeared even though we're not using typescript so now we have a very basic authentication system when we open the application we have to write the username uh then we sign in and we have a username so that we can link sets to a specific user this is a very simple basic without a password but it helps us set the the different to to be able to use the application with multiple users so let me go ahead and do git add git commit minus M uh basic of um system get push origin main perfect so now that we have a username the next step is going to be to write the username when we add set in the database and then filter when we query them two things when we write we need to do something and when we read as well well um keep up the good work thank you very much uh ANF thank you can you do some project that contain payment method that's a very good question because this Friday we have a tutorial dedicated to that this Friday we're going to uh create a tutorial that will cover inup subscription and uh pay walls and specifically remote pay walls and how to build them and customize f with the best practices so make sure to to stay tuned subscribe to the channel turn on the notification Bell not to miss that one if you're interested in um in payment methods that one is going to be focused around pay in up subscriptions but device ID would be quite interesting yes it would uh you could check that library but again like make sure that that you you follow the rules of the platforms if you are planning to deploy application Chris from Kenya hello Chris so our next steps next [Music] steps as I said first of all we need to write the username when we insert a new set we insert a new set in our components new set input new set input when we motate new set here we need to specify the username ABC for example but it shouldn't be ABC it should be the one that we stored in the global context to get access to it it's pretty simple we we only have to do const username equal use off so now we take the username and instead of hard coding it here we're going to do username and because it has the same name and value we're going to do it like this okay let's try it I think it's not going to work because our graphql API doesn't know about it yet yeah fail to add set that that's because if we look at our API mongodb not even mongodb but Coral 0.1 this is the one responsible for inserting a new set we see that the document has of the type new set the new set has this type let's add here a parameter called username of type string and it should be required now if I'm going to make sure that the steps and deployed and if I do add again it still fails to add it let's try to reload probably and uh say bym sign in the first one and here let's do two three add it worked and I can go into the mongodb I can refresh and I can look at the last one it has already multiple um pages but the last one has the username Vadim the first step is done it was pretty simple what we had to do is make sure that our graph API expect this username uh in the new set document and send it when we when we press on the add button the next one is going to be filtering inquiring only inquiring only the sets for a specific username that's going to be in the sets list let's check first of all the API I'm going to open mongodb because this is where we do we query sets and and we see that we have this filter that works with the exercise let's add a new filter that will be user name which will be also a a required string and we're going to send it all the way to mongodb by adding here comma and by adding here name not name but username and let's copy the same syntax from here and say we want to get the parameter with the same name as we specified there username make sure you don't have a comma at the end and I think now it should work it deployed and the thing is that we need to send this variable username of type string in our uh application components sets list we see that our query uh uh only has the exercise let's do the same for dollar sign username of type string uh required then the variable username is going to be this username here with only $1 sign now when we execute it in the variable array here when we execute the the request we need to pass here the username where do we get it from we get it from const username equal use off you might think should we add the because the exercise name we added in the query key should we also add the username in the query key the answer is most probably not uh because all the queries in the application at a at a specific time they will have the same username so unless you are offering somehow uh the possibility to have like multiple accounts and switch easily between them I think Instagram is doing this where you you are logged in in multiple accounts at the same time and you can easily switch between them in that case yes you might want to add the username to the query key because uh otherwise sending the same request from multiple users will override the same query in our case we don't expect the same at the same time to have multiple user signed in so that's why I'm not going to add it to the query key now let's refresh I'm going to say V if I go to the second one there are no exercises if I'm going to go to the first one we see one I can add one more like 50 100 add it's going to add it here if I refresh and simulate that okay I'm signing in with a different user called test if I sign in and go to the first exercise we see that there is no history of repetitions and I can add here 1,000 1,000 add it's going to appear here and if I go back and sign into my account called VM and go to the first exercise I'm going to see only my sets and not the one for the test user so now we have successfully assigned uh sets or data in our database to specific users we are doing this both when we create we assign the username and when we query we are filtering based on our own username this way everyone sees his own data get ad get commit um link set to users by username perfect so that means that our second goal for for today is finished we have linked sets to a specific user we still have three goals for today I want to implement charts for progress I want to implement searching and filtering and pagination probably I'm going to do charts at the end because as we are still working with the API we can implement this um probably it's not going to take a lot of time chart is a bit more complicated I'm going to leave it as a cherry on the top how is it going guys still following along oh right let's think searching and filtering or pagination first probably pagination probably we're going to get into the pagination first is this is I think the most important thing because at the moment sorry for eating but I need energy because at the moment M if we look at the home screen we only see let's say sign in we only have 10 exercises and we cannot load more but the API the data source has a lot of exercises so by simply by simply implementing the pagination we're going to be able to load more items there so to understand pagination we will have to implement it or understand how it works at different levels at the lowest level we have our rest API from coming from API ninjas let's see how they handle pagination for that let's go ahead in V documentation API I'm going to search here exer sizes and we see that there are parameters and there should be offset number of results to offset for pagination default is zero so if we default is zero it's going to take our first page if we say offset 10 it's going to skip the first 10 exercises and will return us the next 10 ones so this offset if we send it in the request it's going to give us different responses like the next ones um the next step is going to be our graphql so from graphql we need to somehow send the offset to API ninjas probably and definitely we need in our graphql this to be a variable because again this needs to be changed differently for different requests so let's go ahead and open our API and open exercises folder index graphql at this moment our endpoint is sending the request to exercises and it has two variables muscle and name let's simply add here the offset of type int it should be an integer specifying how many exercises should we skip before returning now I'm going to check if it was deployed uh there was an error yes because we don't need dollar sign here dollar sign is in a different place if I check now all done deployed let's check the dashboard so if I go ahead in the and refresh and check the Builder yeah have a set now already need something else but but I'm going to look at the exercises actually and if I only take the name what I don't need this one and it's not set but exercises if I execute this query we see a list of exercises until inclined hammer curls if however I'm going to send here the offset how many 1 2 3 4 five 6 7 8 9 if I'm going to offset with nine the first one should be the next page so it shouldn't even be inclin hammer curls actually it is because there are 10 I didn't count them correctly so as you can see by simply sending offset here different value we are looking for the next page perfect that means that we can go in our application in our react native and see how we can Implement there the the the pagination let's go in our source application index because this is where we are querying our exercises at the moment we have variables for the muscle and the name let's add the value for our offset of type int and let's send it to the offset for query of set like this uh offset fail to fetch data because exercise is query needs offset zero will this work yes it starts with this one if I do offset 10 and refresh it will be the next page uh okay but we want to be able to load more you know as we scroll we want to be able to load more how will we be able to do that well I'm going to start like later we're going to automatically do that but I'm going to start with having at the end of a flat list a button here a button imported from react native with a title load more and on press it's going to be load more let's define this function here const load more equal to a function and let's start by console warning load more to see if pressing the button will work if I press load more we see if it works that one okay good I'm going to start with offset zero of course and let's go ahead in our um the documentation of uh rect query to see how pagination works with react query here is a page for pagination but this is for examples I'm going to get into getting started paginated queries rendering paginated data is a very common UI pattern uh and it just works by including the Page information in the query key query key page however if you run this simple example you might notice something strange okay but I think this uh this is a way of having like actual Pages where you move from one page to another what we actually want is to append stuff let's see let's scroll through it uh infinite query results with placeholder use infinite query hook I think that's what we are interested in infinite queries by loading more data load more data because in an mobile application we rarely have like the the UI of the ux of switching from page one to page two P page three what we want is to scroll and to have an infinite list that paginates and loads the next set of items so for that we have infinite queries rendering list that can additively load more data onto an existing set of data is also very common UI pattern uh the T query supports a user useful version of use Query called use infinite query we querying this type of lists when using use infinite query you'll notice a few things are different data is now an object containing infinite query data data Pages array containing the fetched Pages page perms containing the page perams used to fetch Pages the fetch next page and fetch previous page functions are now available F next page is required initial page okay okay so let's start by switching from a use Query hook on the exercises screen to a use infinite query hook use infinite query use infinite query uh use infinite query query key query function initial initial page per Ram get next page per Ram what function is required there that we don't have get next page per RM this is required right get next page perm last page or pages I don't know let's simply say that we will return return 10 for now and what else what else is required [Music] there initial page the only difference is that we are not working with actual Pages we're working with offset base so it's a little bit different and the data right now is not an array the data is an object with different pages so data here H I'm I'm wondering if there is a a way for this offset base one second Let's uh look for it if your AP doesn't return a cursor you can use page peram as a cursor because get next page get page current page you can use it give you next PR page last page Lal zero uh initial query placeholder mutation query inv validation yeah this data I don't like what the data has is an object Pages uh data or let's say the following on exercises equal to data do Pages dot I want to Flat this data. Pages it's going to be array containing the fetched pages I want to flatten this m this this array will that work let's see because from an array of arrays I want just one array of exercises uh canot read property length of undefined where did we read the length let's do console log exercises if I check the logs let exit exercises I think it needs to be a flat map where from the page we're going to take the exercises my yes it works so it has the first list of items that's good and the next step is going to be to load more to load more we need to call a function fetch next page fetch next page so this function will be called in the load more or actually we don't need the load more we simply need to call fetch next page when we press on the load more button load more it actually loads more and if I'm going to press once again it's going to load more but as you can see it repeats because in our get next page parameters we are using this 10 what we can do is let's see get next page parameters last page were pages so Pages this is last page and Pages we need the to calculate the sum of all the pages so p Pages dot one simple way would be to assume that every page has 10 items so to do Pages uh 10 and in this situation initial parameter should be zero initial page parameter but we are never sending it there h Rick Rick show carry if I load more it's the same yeah because offset wait a second initial page parameters fetch project and the fetch project has page parameters okay the function in the query function will receive the page parameter that means that the query function here will receive page parameter and the page parameter is the value that we return for example this one so it we're going to send it to the offset now if I'm going to refresh the first one is RI shock carry this then incline the last one is incline hammer curls I will load more and what we see is is the next page straight bar wrist roll up the last one is single arm paling dumble if I do again Romanian deadlift so as you can see these are actually different exercises military press then we go into seated finger Cur finger seated finger curl I don't know what's but you can press on on it where is it seated finger curl and you can see the instruction hold a barble with both hands in your palms okay so this way we implemented the pagination with a load more button nice nice I like it um I also want to show you how you can instead of having this button how you can automatically do it because if you have used like this infinite scroll list in applications you know that it doesn't require you to press anything it's smart enough to understand when you get close to the end of a list and then it loads more items it loads more items yeah in the list and you think that it's infinite scrollable but it actually only loads the next page when you get close to the end a flat list is perfect for that it uh it supports us in doing that so what we have to do is uh for a flat list uh fetch where where is it oh it it's the property on and reached and on and reached uh what we should do is we should do fetch next page right or let's initially say console log something just for us to see console war and reached if we do this let's see let's sign in let's scroll and we see when we actually reach the end we see the on end reached if I scroll up and then scroll down again it again displays there is also this property or and uh on end reach threshold and this one specifies how many let's let's read the documentation actually to to not confuse you react native on and reach threshhold a property of flat list let's search for it it's actually not a property of flat list but of scroll View and a flat list is actually a scroll view it's not even a scroll View bought uh what's it called virtualized list so here if I'm going to search for this threshold we see uh how far from the end in units of visible length of a list with the trailing edge of a list must be from the end of a content to trigger on end reached a value of 0.5 will trigger the function when the end of a content is within half the visible length of a list the visible length of the list default is two so if two items are visible in the list if two items left are visible to be scrolled then our function is getting called because we're going to load more and we're going to scroll where it's going to be actually two screens I think if it's one it's going to be a full screen as you can see based on the scroll bar if a full screen is left for example below a single arm if I scroll it reach it displays this so that means that we have exactly one screen size and that's how it works it was exactly one screen size of items so value of two I think is okay a value of one to have one screen size below and when we get there on end reached we need to call fetch next page uh by actually calling it or let's do it like this and we don't need the button anymore because now everything is going to be automatic as you will see initially we see a list then just pay attention at the scroll bar as we will scroll it will get smaller because it will load the next page it got smaller then it gets smaller and as we scroll it gets smaller and smaller until we we get till the end and that's how we Implement infinite scrollable lists and pagination with uh all our setup I think there is also there is fetching next page and maybe we can check if it's fetching next page not to fetch the next page but maybe that's working automatically I don't know because if it's already fetching I don't want to fetch again is fetching loading more yeah here I oh it's disabled if it's fetching next page so that means that yeah I will also do here let's add a function or let's do that let's go back to to having a function load more here load more load more let's do const load more equal if it's not fetching or let's do if is fetching next page I want to stop because I don't want to load more otherwise I want to fetch next page this way we are sure that we are not trying to fetch the same page twice as we scroll for application oh perfect awesome so that was our pagination so let me go ahead and do G add get commit minus M pagination and that's our next goal accomplished for today pation pagination here it's done let's go ahead and in The Following part Implement searching and probably only searching for now maybe filtering is going to go later but not sure if we're going to have time because filtering is very similar to surching the only difference is the UI you need to to to specify like some kind of model where you set the filters that you want to to work with uh hello everyone in the chat how are you doing guys following along let's get some uh some more snacks in if you're enjoying it so far guys don't forget to subscribe to the channel That helps us a lot for all right enough snacks let's go ahead and continue with searching for searching first of all we need the user interface for the search bar right um the UI for the search bar either we can add it ourself here or we can use the search bar that is coming from the platform for from a stack Navigator and for that I'm going to look at the react navigation let's go to the documentation of react navigation because yes we are using uh exper router but behind the scenes exper router is using rack navigation and here in the guides I need to look at them where is it Navigators let's go to the stack and here something like search where is it initial search header search bar option this is from native stack actually coming and by setting this header search bar options we can enable the default uh way to to render a search bar is it only for iOS only supported on I oh yeah only supported on IOS and Android so we need header search bar options on our stack screen the stack screen that is our home screen with a list of exercises to do that we first of all need to before the flat list we need to get to provide some options to the Tex screen options and here we need as you can see the option is called header search bar options if we just add this one if I'm going to scroll up no it's not going to show up let's see what we have to provide here autof Focus bar tint color cancel button disable High hi navigation hide when scrolling input type placeholder let's do a placeholder Veer called search so if if I scroll up it's hidden if I scroll down it's going to appear here at the top which can cancel and we can write something here and then to get this value we're going to have to hook into a call back function called a callback that gets called when the search bar has lost Focus onchange text that's what we need and this is the event and in the header here let's assign this we need a state variable where we will store the search uh information so let's call it um search set search equal use State empty string initially so if I write something here and then press enter we need to execute the the search and the to get the to get this search bar or to execute a function uh we can do that either when the search term is changing but in that case you either have have to debounce which means you have to control how often you are sending this request to your server or you're going to send a request for every single keystroke like for every single letter and that can add up to a lot of uh requests and in in a way like that's a good user experience because as you're write it's going to send these requests uh but I'm going to actually send only one request after we lose focus after we press enter so that is going to happen uh by sending here on blur um run search or something like this H do I want to do it this way or maybe maybe maybe I'm going to do it in another way maybe they use infinite query has some kind of a debounce react uh query the bounce I think it should have automatically use the Bounce from where uh for there is no yeah let's see this example the bounced search term for that we're going to have to install the use hooks let's try that um maybe we're going to do the search without de bouncing first just to see and to do it like step by step and then we are going to debounce it for example what we will need is uh for to specify the name when querying the exercise our API is ready our query is ready only I think is that we need to send it here so the name will be the search term and because the search term is uniquely identifying the the query we definitely need to add it in the query key exercises and here search so if I do here viim initially it's going to probably show all of them but if I do uh bench it's going to be dumble bench press close G bench press weighted bench press bench press and so on so it works but the problem is that it sent a request for every letter that I wrote so I wrote here five or six letters it sent six letters to the uh to the server so every keystroke it shows something also we can also show um this there is a property called Old Something old data well yeah let's let's first of all debounce it to solve this problem of sending too many queries and only sending it like once a second uh maximum so we're going to install this um uh hooks library and let's check the example yeah the bounce search term after the search we're going to do the bounce search term use the bounce imported from from this library that we just installed import use the Bones from ui. da use Hooks and we're going to have a search here and the value like it's going to send maximum every half a second or we can do every 1 second and now we're in the query we're going to work with the debound search term both for the query key and for the value that we send here so let's do VM sign in if I do a search bench you see only after I stop writing uh it and uh not more often than once a second it does this bench press wait bench press goes there and because it uh it queries the the the cach ter ter like if I go back to nothing it's going to automatically show it here but if I write something here and we'll start loading maybe we should better or no I think that's that's really nice like pull up pull okay pull up is like this okay okay that's good you can also do a search do trim here in order to remove like wide spaces from the beginning and the end of a search term and now now it works there is this weird bug with uh the the header size and the first item not being visible because it's below the the search term you can add like some additional pting V to make up for it where we can always display the the header by doing hide when scrolling false this way is displayed here it's always displayed and I can add I don't know to a container maybe some ping top 100 20 50 70 60 so now yeah yeah maybe 150 if I do pull up way did pull up and so on yeah this pting top like this actually should be probably Dynamic like this is not the best solution but at least it somehow works so I'm not going to bother on that I'm going to leave it like this and this way we have searching implemented think it works uh we can go ahead and do get add G commit search exercises and get push origin main all right one more goal accomplished thir searching is finished imination finished finished finished the last two things are charts for the progress and filtering okay the charts will be interesting for the charts we need to use some kind of Library I'm building a a production application for financial management if you go to famifi not justd from here you'll be able to check it out and there I'm using a charting library and I don't have a screenshot for it yet uh the charting library that I'm using um yeah here is the fify application that I was talking about haven't updated the the screenshots yet but there in this application I'm using the uh react native graph Library implemented by the guys at marello um by Mark who is also the offer of Rea native mm KV the vision camera and also this reactnative graph it's working using uh re native skia and renders this beautiful kind of charts um there are some some some downsides of this Library as well there are some issues it's quite basic um I open actually some issues that I get in my application uh but it's quite interesting to to to work with it it looks kind of nice and I think we can we can try to to work with it in our application use content uh incent adjustment behavior for the flat list oh perfect let's see you leave your learn in the index on the flat list content uh inant adjustment behavior and what Behavior do we have automatic and we don't need the padding top and this will work yes okay that's nice I like it I like it like that and I think if we need some space at the top we will have to do content uh container something with style uh is it style here pting not sure if any everywhere but at least on the top sign in yes it has yeah perfect and to to have a the scroll bar at the at the end what I'm going to do is instead of having the container having this podding I'm going to put the podding on the flat list and not on the top but around everything so now the scroll R Bar is all the way till to the right that's much better here bench perfect let's do get add get commit fixed flatlist scrolling behav thank you very much for the advice totally forgot about that V code theme it's a material darker or something like that material this one material not them I material theme and I'm using the color color scheme it's material darker I think that's how it's called I don't have any more past tachos found one all right so graphs right all right so let's go ahead and start working on the graphs what I want the goal of this is where we have for example uh here where we have multiple sets uh based on different dates I want to display them on a graph with um on a graph to see the progress that you are doing for vent we need a couple of things you know one of them is is to know when this was added like the the date but okay that's going to that's going to come it's going to come in a moment let's go ahead and just install and set up the graphs so that we can see it and then we're going to think about like data that we need so let's go into as I said we're going to use the react native graph from marello uh let's go ahead in the documentation and we're going to need to install a couple of dependencies the first one is react native reanimated let's go ahead in the react native reanimated and follow the documentation maybe we're going to even open the documentation to install it in our application getting started uh with npm no we need installation npx Expo install react native reanimated let's go ahead head and do that hopefully it's going to work with a with the latest version of SDK because yeah it requires a couple of heav dependencies like rective ski and so on uh we need to add the animated B plugin in the B.C config so let's copy it from here let's open open Babel config file and here under plugins let's add ver react native reanimated correct then what do we need to do it needs to be listed last we need to restart but we're going to do that later okay that's it with setting up reanimated next one is gesture Handler again let's open it up and let's follow V documentation to install and set it up view documentation installation uh and we're going to go with I'm going to just copy the name because I'm also oh come on I'm also going to use npx Expo install react native gesture Handler oh come on uh npx Expo install gesture Handler after it's installed let's see what additional things we need to do uh after installation we need to wrap our entry point with gesture Handler root view so let's import it and inside our our application layout this is the the entry point in a way the root layout let's import the juster Handler and let's wrap everything into the gure Handler root view as per the documentation it also needs this style Flex one to make sure that it takes the whole page as we can see here perfect and that's it for the gesture Handler let's close it let's close it and the next one is the Shopify R native skia let's open it a new tab let's open the documentation documentation and let's zoom in a bit let's see the Expo uh Expo rective skia I'm going to go into the export documentation uh to see H basically to copy the npx export install command clear again npx XO install Shopify nitive skia and I think that's it we don't need to do anything else yeah we don't now back to here the last step is to do npx Expo install react native graph finally the library that we need npx Expo install R native graph let's go ahead and restart our development server that is running the Metro bundler for our re native I'm going to stop it and I'm going to start it by providing this clear command to clear the cache let's run into an iOS simulator and reanimated the version native part of reated why I know Let's ignore it now when we are on a page of one exercise I want to display a panel with a graph for that let me go ahead and create a in the components a new file called uh progress graph or progress chart GSX let's simply return a functional component for now that will render a text and I'm going to open it in our application and use it in The Details page the similar way as we have here new set input I want to render it above a new set input uh how did we call progress progress graph and it was automatically imported from for us from the components that we defined uh I'm going to let's add some Styles here Styles Styles equal Styles shit. create and there will be this container styles that I want to do to match the other panels that we have there styles. container for example I'm going to do look at the new set input and here we have this container with background color with and so on just like that yes they look similar progress graph okay so now we're going to work in this progress graph to render starting with a dummy chart and then we're going to think how to use the information the data that we have from the user to display a proper chart so what we need to do is we need to render a line graph by providing the price history not the price history but the points so let's start by importing line graph from um react native graph let's go ahead and render this line graph here and we see that it requires some properties one of them is the points which we can in initialize with an empty uh array the other one is animated and the animated should be be false let's let's start with animated false and the color let's go with this one so let's sign in go to an exercise and the price graph is there let's go ahead and give it a style uh styles. graph well not like this but below I know I'm going to give it a WID of 100% and a height of 200 pixels something like that maybe a background color gray it doesn't actually need the background color we know that that box is our graph because we don't have any points that's why we don't see anything yet so if I'm going to go ahead and Define here the points initially an empty array and send the points here still not going to show anything but we're going to be able to go ahead and Define some actual points the points should have a following properties it should have a date and it should have it should have a date and it should have a value but the date what yeah the documentation is still like needs a lot of work date well line graph I'm going to look through the source code to see line graph props there should be points where is it oh here graph point value and date and date should be of actual date uh object so that means that we will have date new date and value for example 10 and then another point there with another date and another date and so on uh in JavaScript let's go ahead and uh initialize the date how do we initialize the date JavaScript date Constructor new date year month year 2024 is it month December yes 01 01 then we have 0 1 02 and 0 1 03 15 and this one is 20 what's happening hey what's happening come on XO goal workout okay now going to the first one hopefully we should see something yes we see something and if for example is going to be under know 16 here we're going to see how everything changes and of course if we add the next date here like the fourth m 17 we see all of this plot plotted on the the graph on the chart nice so okay we we are able to see the progress we are able to see the graph now we need to somehow get the the right data to display v let me go ahead and do a commit now uh render integrate react native graph okay give me just one second I'm going to be back in very very quickly and then we continue for all right uh so now that we have the graph displayed we need the actual data about the sets that we have in the database to plot them on the graph for that as you can see we need need a date and a value and currently our set doesn't have a date nor does it have a an a a unique value yeah it has reps and weights but what which of them are we going to plot I don't know uh another way is about the date currently our sets do not have a date the think is what happened to my camera hello hello hello camera hello let me try to restart it no it's blocked very weird hello now it's not even visible hope hopefully it's not broken after 4 hours of live streaming um let me just double check something I think everything should be fine with it all right anyway so probably it's going to be like this we're going to finish the tutorial with how with my face uh let me maybe even hide it from here and we can continue because we uh yeah we we are able to continue the most important part is that you can see the screen uh all right so as I saying we need two things we need a date of our set when we created it and we need a value uh let's start with a date we don't have it uh we might be able to add it whenever we insert it but we can also take it from the object ID if if I remember correctly mongod DB object ID to date to date based on the object ID we can take the date when it was created because it's a uu ID and it contains information about the date and the date and the time so how can we extract it in JavaScript date from object ID mongodb object ID to a JavaScript Tim stamp object ID h oh two string substract 0 to8 let's try this because yeah let's try this one this snippet uh and we're going to try it first of all inside our exercise list item the one that is rendering one exercise list item for no no no no no the in the sets list in the flat list we are rendering items reps weight and let's also render for example the item dot ID this is the IDE of item uh but I want let's extract this to a separate component in order to to be able to calculate some of the stuff so components new file set list item do GSX here I'm going to have rective function export set list item and from the set list instead of in the flat list to Define this text I'm going to copy it move it to our set list we are going to receive the item through properties and we are going to render it in our set list like following set list item and the item where let's call it set is going to be item because we call it set let's go here and change it to set set. reps set. item set. id now everything should work as it was working before but here we're going to be able to do some calculations for example what I want to do is I want this snippet that will help us to transform from object ID so let's do const timestamp equal to the object ID that we want to use in our case that's set doore ID it is already a string so I can do it like this and then const created at is going to be new new this and times temp like this so let's see what do we have here in the created ad dot to ISO string sign in if I go here we see that this one was created 2024 0123 at 1728 1733 it works it actually has the date pared from the timestamp that's nice that's good uh if you want to render human readable dates in the application what we can do is we can import date. FNS let's install it am I was I using data [Music] finess not sure what's the this one looks very interesting the the template but let's go ahead and install uh by doing NP Expo install date FNS and we want to render distance to now like one minute ago one year ago and so on we need to import this one from date FNS at the top so instead of created ad we are going to display format distance to now and we're going to provide the created at date 1 Hour 1 hour yes yes that's that's nice and because we have a separate component I'm going to add a separate view maybe a bit of like the text here let's add a text below for the date not to have everything in one row this text will have the background color and everything like that will go towards this one background color fting border ruse we'll go here we don't need overflow on the text anymore and this one will have style uh uh color gray this one will have font weight bold and a gap of five between the elements yeah now it looks much better um so we started from the graph on the graph we need a date okay we know how to get the date uh the next step is we need a value but maybe okay let's let's uh first uh yeah yeah yeah yeah I know um we're going to start by mapping the sets on the graph and then think what to do next uh the progress graph in order to display something it needs an array of sets right so this is going to be this uh property here sets of a progress graph let's see where we are rendering progress graph and send the list of sets that we want to to plot on the on the screen we are rendering that on the detail screen here so the sets should be our H where sets list oh boy you see the sets are in the sets least but sets list yeah we're going to because we don't have access to the sets inside our description Details page we only have access to it in the sets list uh I think I'm going to move a graph inside to be rendered in the set list Itself by rendering here the wait a second no no no not like this but in the list header component I'm going to expand this one to First render the list header component that we receive from the parent and then if I do it like this progress graph where is it in the detail screen we have this progress graph I'm going to remove it from here and the error in the sets list what's up here don't need it here okay now it works uh and I'm going to render the progress here in the flat list of our sets Pro progress graph imported from our progress graph components and the sets here is data sets documents okay we see progress graph let's go back to our progress graph if you see that this issue that it's not scrolling properly at the bottom that's because uh H don't worry about that something should have a flat list one but now let's do a console log set and here we're going to see the list of sets that we receive our uh let's call them dumy points and let's use them in the graph while we are actually going to Define our points because our points will be based on the array of sets and we are going to map over them and for every set we need to return an object with date um new date and the value for the value it's simple because we can take the set dot uh Reps for example and I will also default it to empty array in order for this not to give us errors if now I'm going to console log points after res sets what I'm going to see oh my computer starts to come on what's Happening workout I go here we see an array with date value two value 50 that's our repetitions okay uh for the date we remember how we can transform that uh we did that in the set list item for the created ad maybe we can put this into a uh yeah let's go into the progress graph and let's define it as a function uh object or ID to date we're going to receive the ID and we are going to return this one not set but uh ID like this substring and now we can use this function ID to date uh to transform our set doore ID to a date now if I look here we see the correct dates perfect and I think we can try to switch from dami to actual points if we do that we see uh the changes from from what we have if I'm going to add a new why is the new input at the top well yeah I know why it's at the Top If I'm going to add a new uh repetition here for example 20 30 OD it's going to look like this 30 28 and it doesn't change a lot in shape just because all of them are at the same hours and dates if I'm going to manually go ahead but I'm not going to be able to change the object ID you know that's going to be tricky to do uh I think there is a ob object ID or times object ID to Tim stamp online there is a converter so I can take an existing object ID from here is it this one I hope it's this one and I can change for example the date from 22 to 20 take back byid and update it here we let allow me to update no it doesn't allow me to update but I can um duplicate this for the ID I can specify that one and I specific ID that I created for the Reps I can do 20 or let's say 12 weight is going to be 30 insert now I'm I I hope that I added a new item in this Rick's carry that is older like three days ago so we see it here and I can do one more for for example 17 I will take this one let's duplicate this change this one and I will do less repetitions 25 insert now if I go there yes we are seeing a progress and we see from six days ago all the way till today that we are moving along and instead of uh plotting the sets what you can do is you can plot the volume and the volume is a better approach because it takes into consideration both weight and sets so in the graph for we don't need the dummy dummy points anymore we can delete them uh so for the value we can multiply reps by multiply reps by set. weight and in this way that's going to be the the volume sign in let's go here yes we see the volume there if I'm going to do console. log points let's see what points do we have value six value 600 value 200 yeah the the ranges are all over the place that's why the the graph looks this way but you can also add like if you look into the documentation of uh of the graph of retive graph you can also add um you can also add Pine gestures to be able to move between the items and you can also add the range if you want to specify what range should your values be so that was the graph I'm supery happy that we managed to implement it uh you'll probably have to do some checks for example if you're going to an item that doesn't have anything yeah it doesn't show the graph at all so not a problem uh with that being said I'm going to go ahead and delete the console logs that we have here and I can do get ad G commit minus M graph uh graph data from database perfect get push origin main all right guys so that is another goal for today its charts and graph for our progress the only thing that we didn't do is the filtering but it works quite similar with the searching uh from the API standpoint if we look into the exer sizes uh for example in the application index in our query we already have for example the muscle and we can specify what muscle do we want to filter on the only thing that you have to do is add the user interface where you can select a specific muscle for the filtering and everything else is going to work just simply um add the muscle in the query here other state VAR variable for the muscle update it when you change the UI and in the in the query function besid the name add also the muscle here and that way you will be able to filter based on a property you can check the API documentation because you can filter based on other parameters as well not only muscle but difficulty as well and so on and that was everything for today guys uh if you enjoyed this make sure to subscribe to my channel I cannot switch to my camera because it actually doesn't work uh and I think we have to to end this uh make sure yeah uh this Friday we're going to have another tutorial uh we're going to have another tutorial for implementing monetization with uh Revenue cat so make sure to stay tuned subscribe to the channel turn on the notification Bell not to miss it out and yeah I hope you enjoyed this whole project that's the the end of it and uh I encourage you to take it to to to the next level make this as a starting point and Implement other features Implement continue working on a workout tracker it's a great way to exper experiment learn and Advance as a re native developer all right that was it for today guys thank you very much have a nice day and I will see you in the next live stream bye-bye
Info
Channel: notJust․dev
Views: 53,911
Rating: undefined out of 5
Keywords: vadim savin, not just development, notjust.dev, react native live coding, live coding, javascript, react tutorial, react native tutorial, javascript tutorial, react native ui, react native for beginners, Full-Stack Development, MongoDB, Workout Tracker App, Fitness App Development, GraphQL, IBM Stepzen, Expo, User Interface Design, Fitness Tracker, Workout Log App, Mobile App Development, Backend Development
Id: 7MbFDnR_6HM
Channel Id: undefined
Length: 239min 11sec (14351 seconds)
Published: Wed Jan 24 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.