React Native Full 8 Hours Course (Expo, Expo Router, Supabase)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what's up Noz developers Welcome to our newest Workshop today we're going to learn and we're going to build a full stack food ordering application using react native and super base this is going to be a Zero to Hero tutorial and we're going to cover in depth a lot of topics that goes into building fullstack mobile applications all the way from idea until you get them on the market the plan is to upgrade your skills and to go from knowing a bit of rck native and having little skills of building applications to being a master of it and being able to build any type of mobile applications using rack native super base both on front end and the back end the text tag that we're going to use for this Workshop is going to consist of R native on the mobile side we're going to of course use Expo to create our R native application and we're going to use Expo router for the navigation Library everything is going to be done in typescript in order to build types save applications and on the back end we're going to use as I said super base super base real short it's an alternative to Firebase which is also open source I gave it a try in a couple of projects uh before and I think it's a really great solution to really fast build backends for mobile applications we're also going to cover some animations and uh Expo application services including how to build the application and launch it later this sares is going to be split up in three different mod modules the first one is the UI and here you're we're going to start with react native using Expo you're going to learn how to build and design beautiful user interfaces using built-in components and also how to create your own components that are reusable in your application we're going to master data management in uh in our components using props and state we're going to learn how to implement a global State uh management using react context and that is going to help us Define the data for our uh shopping cart and by doing all of this together we're going to master navigation using Expo router we're going to have different types of nested navigations or more complex navigation with Dynamic routes so everything is covered uh in the first part during the UI in the second part we're going to focus on the backend side of application and I know this is the part that is challenging for a lot of uh frontend developers but by using super base it made it quite easy for everyone to follow along and Implement all the features that we're going to do uh there including authentication system to sign in create an account then we're going to design our database where we will store the data for our products wers customers and so on we're going to query and mutate the data from our application and also we're going to implement image uploading to uh store the images in the cloud for easy access we're also going to going to cover real time updates in order to receive updates about your order as you are waiting for it during the last module we're going to cover animations we've reanimated then we're going to uh go through the Expo to set it up and build our application in the cloud and also to prepare it for the stores and we're going to have two bonus features that you're going to find out later so that's the plan if you are ready I'm ready and we can get started but before that a couple of important topics first of all is the asset bundle I always prepare uh some files and Dam data that will help you move along and follow this tutorial together with me so you can download it at assets. n./ Pizza very rememberable and when you will download vaset bundle besides vaset bundle you'll also get a link to the project guide the project guide is the step-by-step guide that will help you follow along and will provide more information about every single step of a way starting with configuring your environment and all the way till building all the components we also have some user interfaces some mockups some code and this is going to to help you move and implement it together with me if there will be any updates to the tools that we are using I'm going to make sure to update them here so this tutorial is going to help you long way into the future so let's get started with our first uh module with the user interface as you know for the r native application we're going to use Expo tools to initialize and set up our project more recently all of the projects that I'm building I'm starting them using Expo because nowadays there are no limitations using Expo and the development experience is much better than compared to rec native CLI there are a lot of tools and uh there are little dependencies that we have to install in order to get up and running so if this is the first time you're building R native applications this is going to be super easy to get started here in the taskboard go ahead and open up the configure your environment page and here you're going to read a little bit about the requirements that you need to have in your environment to get started because we are using Expo the only required dependency that we need is actually node GS so go ahead and open this if you don't have nodejs installed and install the latest the LTS version currently this is the version 18 and if you have that there is no more extra dependencies to initialize a project but we're going to uh get there in a moment let me quickly show you some optional uh dependencies or other tools that are going to help you build this application for example you can install git and I highly recommend you to get used to using git when building a project because we can commit at different points by when building the application and this Services check checkpoints where we can go back if something bad happens with a project there is also that Watchman dependencies for Linux and Mac OS users you can download and this will restart the server as when you do some changes the Expo go tool is a open- source application that helps us run and debug Expo applications without having to install any dependencies like Android Studio or X code so go ahead and install it it's available both on play market and app store and have it ready on your physical device for Next Step then we have a code editor for the code editor you can use whatever uh you prefer my editor of choice is vs code and that's what I'm going to use today and lastly these are optional and these actually take a little bit more time to set up and the main benefit of Expo is that we don't have to do that but in some cases if you want to build the uh your project for n on Native side for IOS and Android if you want to do that locally you would need Android Studio and or X code so you can follow up that documentation on Rec native environment here where I'm also going to pay some URLs to some tutorials that we did which help a lot of people set it everything up but again you don't need that so we can move on to the next step now that our environment is ready we can start by setting up a fresh Expo project so let's open up the next task set up a fresh Expo project and as I said the only dependency that we need to do that is node so if you had node DV here is my version then we are ready to get started so open up a terminal navigate to a place where you keep your project and let's go ahead and run the npx create Expo up we're going to choose at latest to take the latest version of create Expo application tool then we're going to provide a name in this case food ordering and let's uh provide an option Dash T Advan to select a template the template that we're going to choose is navigation typescript this template comes pre-installed with Expo router and a couple of uh screens already set up it's going to help us uh get started quickly and we we will by default have a couple of screens as examples to start working with now Expo will install all the bendices for our newly created project and then we can open it up and start working so after a couple of minutes or seconds our project is ready and we can go ahead and open it with Visual Studio code I'm going to close this terminal I don't need it anymore I'm going to open Visual Studio code and from here we can open our project go ahead and open the directory of a project that was created for us and here it is if we see the up directory components and so on everything is okay before we uh jump into the folder structure and files let's go ahead and open a terminal you can do that at the top by pressing terminal and new terminal and here we can go ahead and start the development server by simply uh running npm start that will uh open the Metro bundler which will bundle all the code and will make it available for us to run it in Expo go application now with your Expo go Application go ahead and scan this QR code and the application will run directly on your physical device in my case Cas I want you to see as well the the emulator so I'm going to run it on iOS simulator by simply pressing I inside this uh window you can also uh run it on Android by pressing a later on by the end we're going to probably also test it on Android because this application will work both on IOS and Android and we need to make sure that everything is working properly between platforms all right so here we have our application running on our device and we should see already two tabs your phone might be in dark mode let's switch to uh light mode by pressing command shift a but you can uh turn it off through the settings of a phone we're going to try to focus on the light mode I will show you also like how you can have both light mode and dark mode anyway this is our application we can uh test if everything is working properly by changing some text on our screen let's go ahead and first open the app tabs index directory and here we should see the tab one text if you change that to hello world and press save without doing anything more we see the uh application hot reloading on our device to uh showcase our new changes so that means that everything is connected everything is working perfectly now what I want us to do is to actually stop our development server so in this uh terminal where our Metro bundler is running go ahead and press contrl C to stop the server because I want us to structure a little bit differently the folders in our application it's a recommended way to keep all the source code in the SRC directory so let's go ahead and create inside our root directory the SRC directory and let's move there with these three folders the application the app directory and yes the component directory and the constants let's move and press yes to update the import it's better to structure it this way because we know that all the source code will be here and everything else regarding the configuration or assets or modules or maybe the back end is going to leave somewhere else so Source directory now contains the app which is a folder specific to exper router we're going to talk that about that in a minute it contains the components which is a folder where we will store the our re usable component and constants some files with some colors for example before we run again our application let's open up Source up layout and fix One Import if you scroll down until you see this space mono font it is imported but we need to add one more pair of/ double dots to reflect the new location of our layout we added it into a folder so we need to go back one folder after you do that we can open again the terminal and we we can do npm start again to restart the the project on our emulator if we press RR two times that will refresh our application and will download the new uh JavaScript changes so everything is working uh as it was working before but now the code is inside our source directory before we uh start uh working on the coding part let's also make sure to import some additional uh data that we're going to need right in the next task so what we have to do is to import that data from the asset bundle here should be the asset bundle and there is that data folder with some dummy data for for us let's drag it drag and drop it inside our assets folder and here we have our orders and our products that's uh everything that we had to do to set everything up and before we move to the next step I want to uh show you a good practice to try to always and often commit your changes in a terminal you can press on this plus sign to open a new terminal and here we're going to run a couple of commands first of all with Git status we can see a list of files that have been changed if the files look okay to you you're going to do git add and then dot to add all the files to the staging area so if you do get status again you're going to see them with green and all the files that are with green in the staging area will be committed after we run git commit minus M and here provide a message that explains the changes in itex project and now if we do get status we see that on Branch M nothing to commit everything good the benefit of doing that is that if after some time you mess up something for example I don't know I remove this one and my application crashes and I don't know what what happened I can go ahead and check the status of the updated files and I can run git stash to basically revert back to the previous commit or remove all the updates that are not yet staged so be careful with this git stash and only run it when you know that you want to lose like track of the changes that you have done after the last commit so I'm going to do get stash and everything is working back to normal so I'm going to try to commit the changes after every single step step that we're going to do and I'm going to also provide you URLs to this commits so you can compare it with your code with that being said if we look here in the guide we have implemented all the changes that we have to do so we are ready to move on to the next page let's go back to the taskboard and our next step is already about user interface so in this lesson what we're going to learn is first of all using GSX syntax to render UI elements we're also going to learn how to work with built-in UI elements like a view a text a image and how to style our components using the style so the end result of this is going to be to render one single item of a product our food watering application is going to be something like Domino's Pizza so that's why we have a pizza image here the title and the price on the bottom that's our goal and let's go ahead and start working on it so the place where we will uh do the work is going to be this home screen so this tab one screen will be the place where we will render our menu basically so let's start from there and we're going to find it in our app directory the app directory as I said is something specific to Expo router and that's how we structure all the screens in our application every file in this folder is going to be mapped to a screen we're going to learn basically how everything works and is connected together throughout this module let's open up up tabs index. TSX and this is the home screen that we see here on the right with the hello world we're going to do our work here and first of all I think I'm want to remove everything inside the view I'm going to leave it only the view here so how does rendering in react and react native works for that we are using GSX syntax and this part that you see here that's what GSX looks like it looks very similar to how HTML Works where we have tags opening and closing tags we have property for these tags and we can Nest them inside one each other for example if we want to render a text we're going to use the text element and we're going to put the text that we want to render here like pizza between the the text and right away we pizza pepperoni here on the screen this View and text these are actually react native basic components so I'm going to import them from react native without confusing you with these themed components going remove this one to keep it simple and a text as you can see is helping us render text on the screen a view is a simple container uh similar to a div on the web that helps us group together elements give them Styles uh and so on so yeah let's go ahead and see what exactly we need to do for this screen as I said let's start with the title ultimate pepperoni and the price here so for the title we already have it and we're going to do another text box for the price for example $12.99 and the price appears down below the next step styling how does styling work to style this component we can do that using the style property and the style property is available on most built-in components like view text and so on and it expects an object so let's add that object and all the styling happens in this object styling is using JavaScript objects which are quite similar to CSS syntax on the web the only difference is the capitalization and so on so for example if we want to increase the font size we can do that using a property font size 20 for example now we see a text is much larger if we want for example to increase the weight to make it bold we can do that using font weight bold this is one way of styling it and that's called inline Styles because we are inlining it together with the GSX which is responsible for the structure as a best practice we are trying to avoid inline Styles as much as possible because they are the lot of noise around our component and the best practice is to keep structure and styles separate so for that reason I'm going to copy this object from uh that we Define the Styles and I'm going to Define it as a new property on our Styles here named title actually we already have it so I'm going to remove that one and add my title to create Styles shets we are using this Styles shet from RE native and here we group together multiple styles that we can later access and send them to our components for example here if I do styles. title we see the Styles being applied here and let's do that for our price as well we Define styles. price here and we need to make sure to implement the price Styles down in our Styles so for the title the font I think we chose a value of 600 which is a little bit less than bold bold is I think 700 so 600 is a bit less font size 18 and a little bit of spacing between them we did that with margin vertical 10 and that will add some margins around the title only vertical on top and bottom for the price uh we Define a color a blue color we can do it like this which looks a bit weird but a better way when we have to a reusable color in our application is to import it and if you remember there is this constant colors and there is the tint color we can reuse that and this way it's going to be very easy for us to change it in one place and it will be applied everywhere else so to do that we're going to Simply write colors do light do tint and make sure to import them at the top from our constants like this now it looks better and besides the color our price will also have a font weight of bold and looks good we can remove this styles for the separator we don't need that and we can also remove the styles for this container because we're going to Define them ourself and now we see that this the titles and the price move to the top right the next step is going to be to see how we can use real data inside of hardcoded data here for that we're going to have to import our product data from our assets so let's do that inside our component here let's import products from a couple of folders above assets data products and let's choose the first product from that list that's a list of products but let's start working with con product equal products at position zero now this product is this object with the name multim pepperoni with a price and with a image URL that is going to be available for you as well so back in our project instead of writing hardcoding the name here what we are interested in doing is accessing the product. name because the name the product has a name so how do we do that well we can think that okay it's going to be product. name but if we just do that it will literally say product. name on the screen so to access JavaScript variables inside our GSX syntax we can encapsulate it inside corly brackets the cly brackets is basically Al a portal from GSX towards the JavaScript context and we can access variables from here we can have conditionals and much more for now think about it as a way to access variables so if we do that we see already that the name is Ultimate pepperoni for the price let's do the same but make sure to leave a dollar sign in front only removing the price itself then with cly brackets we can access product. price just like that we have a product price Veer and if we change the which product we are working with for example to one you're going to see the price and the name automatically change perfect now let's see how we can work with images our product that we are working with has a image URL which is publicly accessible as you can see let's go ahead and see how we can render this URL as a image on the screen for that we have a rck native component called image and we're going to render it above the name and the price so let's start by rendering the image and the image doesn't need anything inside like children so that's why we're going to use a self-closing tag now the image requires I mean has one required property which is the source and the source is how we specify the image itself it can be a local image but in our case our image is a remote image so for that reason we're going to use a object with a URI to specify the URL of the image we want to render the URL we're going to take it from product do image and here we don't have to uh to wrap it around cly brackets because we are already inside the brackets so we already have access to variables so now we would expect the image to be displayed on the screen but it's not there because it also requires some Styles let's go ahead and uh assign it styles. image and let's define the image Styles here in our Styles shet the problem is that without some width and height the image doesn't know how to to render it so if we specify WID 100 height 100 that will render the image as 100 over 100 pixels squar that's how we assign static wave however if we want to do a relative weave depending on the screen size and so on we can use percentage so if I'm going to do 100% here that's going to be full we of the screen with the height we can either provide here the uh a static height or we can provide an aspect ratio and by providing the aspect ratio the height will automatically be calculated based on the WID so the aspect ratio receives here a floating number for example 1/ two or actually two over one we calculate the height as half of our width in our case I want to make it Square so that's why I will have it as aspect ratio one I can keep it like this for now later on we're going to display them in two columns so it's not going to be so the image is not going to be so big now a little bit about styling our container the container has some background color has some rounded Corners some spacing around it so let's start by setting the background color of our container so background color we can specify it as white now we see that the names are basically cramped there without any spacing around let's add some ping to our container and while margin is the space outside the container pting is the space inside the container so that's why it added around all the edges some spacing now if we want to make the corners rounded we can use border radius property and the the higher the value the more the corners will be rounded naturally if you can see very well but you will see it later when we put them into columns and that's it that's our first simple user interface based on some pre-built components from react native such as text image view we learn how to work with them we learn how to style them we learned about inline styles about the style how to access variables inside our GSX and we are ready to move on to the next lesson before we do that I'm going to commit everything and let me call it as our lesson perfect now that we know how to work with build-in components let's go to the next step because the next step is about building your first custom component so we saw how to work with build-in like text view images component what about about building our own custom components for our UI this is a very helpful thing in react native and react to separate everything into smaller components and then use them as building blocks to create your more complex user interfaces and at the same time keeping your code clean and having one single responsibility in this lesson you're going to learn how to create a simple component use it to render it inside our application and also how to use props to data from a parent component to a child component let's go back to our project here and let's first of all talk about what makes a custom component as we can see our tab one screen this is a react native component at the core of a component is a simple function that returns some GSX so if we want to create a separate component for the component that will render one single product what we have to do is we will start by creating a simple function you can do that using the function keyword or you can also do that using the arrow function syntax and let's do that with an arrow function here const let's call this component product list item is going to be equal to a function here is the arrow function syntax that should return something should return some GSX that will be rendered on the screen what GSX will it return well basically everything from our tab one screen so let's copy everything and put it in the product list and uh in the toab one screen what I'm going to do is I'm going to have a view now we don't see anything because we are not using this product list item yet to recap to define a component we create a simple function that returns some GSX on the other hand to use it to render it in our application we're going to do that in a very similar way how we used the build-in components for example an image we use the angle brackets we use the name of our function and we close it if it doesn't we close it right away with a self-closing tag if it doesn't need any children and just like that we see the component rendered on the screen but now if we want and we have to render it for example twice we will not copy paste a lot of code we will only copy paste the way we render it and then another benefit is going to be being able to use the same component in different screens and different parts of our application but that's the first step because yes most of the times we need custom components for basically replicating and rendering the same type of elements based on different data for example a list of products on our menu they will basically have the same structure with an image title price the only only thing that will be different between them is the data that they will use the name the price and the image itself everything else like structure and styles it Remains the Same so now the question is how can we send data to this rendered product list items to our custom components and based on that data display different things on the screen well here is where props come into play and we are using props to send data from a parent component to a child component in our case the parent component is the tab one screen or maybe we can even call it menu screen because that's going to render the menu the parent component is the menu screen and the child component is the product list item starting with sending this data we already used it with maybe without even knowing about it for example here in this case we send the style property to the text this is the syntax of sending a property we start with a name equal and we give give a value so let's do the same here in the product list item let's send the product data that should be rendered there we do equal sign and the corly brackets to be able to access JavaScript variables and the variable that we're going to access is the products array at position zero for the second one we can send a different product in a similar way but this time position one that's how we send data now how do we receive it inside our product list item we receive it as the first and only uh parameter of our function so let's call it props and if we console log the props and open the terminal where our application is running reload the application we should see two Logs with two objects inside the logs we see a key called product that has information about the product that should be rendered so that means that all the properties that we sent here will be put inside an object called props here and what we can do is right away destructure the data that we need out of the properties and the data we destructure it by name so if the name of the property is product we're going to destructure it with product name if I do that I can also remove this um line with and if we do that we already see that the two products that are rendered on the screen they are rendering different data different images if I change here from 0 to 5 we're going to see right away that data changes that's how properties uh of our component helps us send data from a parent component to a child component and render different things on the screen having these properties our component uh here is complete and before we finish this lesson we uh have to move it out of this file as a best practice it is recommended to have one component per file and here we have actually two the product list item and the menu screen however this file is specifically about for the menu screen so we have to extract our product list item from here to its own file to do that let's start by creating a new file inside of our components with the same name product list item. TSX let's go ahead back in our application tabs index and let's copy actually everything move it to product list item and simply remove the export default function menu screen one last step is to make sure that we are exporting this component from the file to be able to use it in other parts of application so let's do that with export default and the name of our component we will also have to make sure that our relative import Puffs are correct so I can remove a set of these double dots and and the products we don't even need it here so I will remove it completely and everything else including the Styles specifically for the product list item so that means that we are done here now let's move back to our tubs index from this side we're going to remove the component and instead of declaring it here we can import it from the file that we just created just like that and then we see that we don't even use the Styles in this uh screen so I think we can safely remove them and remove some of the unused Imports as well for example colors Styles sheet text and image are not used so just like that our home screen or the menu screen became very small and very clear like what it is doing is displaying a manual list and the product list item as well is quite small and only has one responsibility to render a product in a list okay so let's go ahead and create the Commit This was our your first custom component all right so we are doing good progress we extracted and created our own product list item component but you might see that uh there are some red underscores for example here for the product saying that it has the any type what does that mean well that means that we haven't properly typed our component using typescript and because we are using typescript in this application we are not required actually to type it because as you can see everything works as expected but we will get a lot of benefits if we properly type our component so for that reason uh in the next lesson in the type save components we're going to learn how we can create type save components and also we're going to implement some experimental features with typescript aliases but first let's go ahead and import the types file from the asset bundle to our source directory so here we have a source I'm going to find the asset bundle and there is the types folder here let's go ahead and drag it in the types folder this file contains some predefined types that uh we will need during this project for example a product is a type with this fields it has an ID that is of type number it has an image that can be either a string or it can be null when the product doesn't have an image and it has a name of type string price type number that's the data that one product needs and if you look into the assets data product this data follows the same type and has ID name image and price now let's use this product in our product list item we're we going to import product from double dos V types and now what we have to do is to say that this product is of this type this variable is of this type how do we do that well we have to specify what is the type of the properties object of our component we can do it in line right away here but I usually like to have it separately just above a component as a type product list item props so basically I take the name and then I append the props and here is equal to an object now we need to specify what data what properties do we expect to receive as you can see we depend on a product property so let's add it in our required types product and with uh after the dots we need to specify what should be the type of this product for example it can be either a string a number or some other variable as well in our case we Define the product type in our types and we know that the product should be of this type which means that it should have an ID image name and price we are not done yet because we need to specify that this product list item the properties is of our type to do that after we D structure we're going to specify the product list item props now if we hover over the product we see that it's of type product and here is right away a example how typescript can prevent us from doing bugs or from Shipping bugs into production because without specifying that typescript never complains when we are using this data product do something but maybe we made a a typo for example here we put name one we don't see that bug we ship a product and we find out that hey the name is not showing up here by specifying the types type script will catch and say that hey the property name does not exist on a product did you mean name yes I meant name and I made a typo another bug that it shows us is here under the source it's quite a long and sometimes hard to understand but basically what it says is that the image URI of type string or null is not assignable to the image source URI should be string or null in our cases the image expects a valid URL for the the image but our product can have a missing image for example if we go ahead in our data and remove some images in our products if for example for the second one I'm going to maybe comment out this image in that case we're going to have a problem we see that the image is not being displayed there on the bottom and without typescript we wouldn't have known that so what we can do is we can provide a default or fallback image if this one from the product is null to do that I'm going to give you a URL default Pizza image and it has basically the same structure of a URL as the other products so for example you can copy it from here and at the end simply add default.png then we can use this default image as a fullback image by using the or operator and we're going to say default Pizza image and the error the typescript error went away and what this means is hey for the URI use the product image if it exists if it doesn't exist fall back to the default uh Pizza image that we have here okay perfect so now we see that the first one displays the Right image the second one displays this uh default image with basically no pizza so that's how we defined type saved components the benefit is that specifically when you're working in bigger teams the components that you are working on are not only used by you they are used by your teammates as well and by specifying what type is the properties that a component expects the other teammates from your work will uh see that whenever they will use your component for example if I go to up tabs index here we see that the product Oh the actually doesn't match oh yeah undefine is not assignable to type product that is coming because I commented out this one and if I go back to our tabs index now yeah like the the product if we don't send uh the required property typescript will let us know that the product is missing if you also send something that is not of a expected type it will also inform you so this is uh very good to make sure that you are building applications with less bugs anyway that is our property and the next part that I also want to show you in this lesson regarding typescript is the new typescript puff Al support so what are they how we can enable them and how they can help us well let's actually enable them and in a moment you're going to see the benefit of using them so to enable them probably if you're watching this later this might be already implemented by default but at the moment of recording this uh tutorial what we have to do is open the app. Json and under the experiments we need to enable a new experiment called TS config Puffs enable through now what we can do is create aliases inside our TS config here in the compiler options so what we can do is we can first spe specify the base URL as the root directory and after that we can specify a list of aliases that will map from a string to an actual puff for example we can specify that whenever we import it as at component then anything that comes after that will be mapped towards Source components than anything else the benefit of using it is now whenever we are importing something from the components folder instead of using relative Puffs I will open the our home screen the menu screen so instead of having this long relative Puffs we can simplify it by using add components probably we will have to restart the server to to make it uh work but before that let me actually add a couple more for example the usually we have this ad mapping to our source directory so anytime we need to import something from Source instead of a lot of relative Puffs we can simply do add/ something uh it's going to be source and it should be an array here and I also want to do copy paste the components and do the same for assets this way we can also but it's not going to be from Source it's going to be directly from assets will it work oh I don't I don't need that add/ components I need add components and the same thing with assets as well well so that was my mistake if I reload everything is working back again but now as I said we are importing a bit easier without having like this long relative imports from assets we also Define it as at assets and that basically means that whenever it encounters a puff that starts with at assets because we Define it here as at assets it will basically replace it with assets from the root directory so that's how it works and that's how it helps us import easier things from product list items for example we can do here constants we can add like more where we can use the source and so on I'm not going to update a lot here but from now on I'm going to try to use the alas Puffs because it's easier to write them and then uh you can easier move your components in different folders without having to worry about the relative Puffs being broken with that being said I'm going to go ahead and commit everything and and we can move on all right so that is it with types saave components now we have a reusable and typ saave component that we can use for rendering product list items at the moment we are rendering two of them here on the screen but they are not scrollable and probably that's not how we are rendering lists of items in this lesson we're going to learn about flat list and how to use it to render scrollable lists of items let's let's do it like this I'm going to comment out this the rendering of these two components to have an empty screen here now let's go ahead and start working with a flat list a flat list uh helps us render infinite scrollable lists such as the Instagram feed and so on it's quite easy to get started uh we simply import the flat list from react native and we can render it in our application like this flatlist and self closing tag a flatlist has only two required properties that is the data which should be an array of items that we want to render in our case the array of items is products the second one is render item this render item should be a function that tells flatlist how should one single item from our array be rendered so with this information render item should be a function let's declare it as a function here we are going to return how we want to render one item from the array of data we know that to render one item we specifically for that we Define the product list item so if we do it like that we're going to render already a scrollable list the problem is that it only renders the products at position one for example here so how do we specifically render the item that currently the flatlist is rendering for that in the function properties here we're going to receive an object of informations one of that information is item and we can destructure it from the that object and we can simply send this item to our product because the item will be one single item from our array so this for example this one we know that this is a product so that's why we are sending the item to the product now as you can see see we have a scrollable list with different products with different images rendered on the screen perfect and it's as simple as that now I can remove this comment and I can probably even remove a view around the flat list and only leave the flat list as I said it's quite easy to get started but at the same time flatlist is a very flexible component that allows us to do a lot of different styles of lists both vertical and horizontal what I want to do for for our application is to first of all render items in two separate columns to do that the flat list has a property called num columns which stands for number of columns we can specify it as two it doesn't support changing in on vly so it will render an error but if you press RR double time it will reload but the thing is that it doesn't yet display it into columns even why it's trying the problem here is with our product list item itself so let's hold command and press on it to open it in a new tab and the problem is with our container itself the thing is that the container does not specify its WID and the image specify with 100 so what it's trying to do is it's shrinking and not leaving space for the other column to avoid that we're going to add a flex one property on the container itself and what that will do is it will split equally the space amongst its siblings so because we have two columns here it will split the space in a row equally between them and if it's going to be three of them as well they will fit properly on the screen that's how we can render grids I'm going to move back to two and we can cover a little bit about the styling itself for example uh there is no space between these items there are couple of ways one of them probably the easiest when you get started you would go ahead and add the spacing on the container of our item for example by specify margin 10 and just like that we have space around all our items but there are some other ways of doing that as well and these are the Gap property introduced very recently in rack native what we can do is specify the gap on the parent component and that will put this spacing between the items to do that we can use the flatlist content container style which is the Styles supplied to the container of all the items so if I add here Gap 10 what we will see is a gap between the rows if we want the same gap between the columns there is another property of a flat list called column rer style and this is the styles for the wrapper uh around the columns so if I add Gap here 10 that will add space between the items and lastly if we need space around the whole um flat list we can do that in the content container Style by adding here padding so even though this solution requires more properties like three of them Gap Gap and ping sometimes it's better to do that because for example in this way the the flat list itself the scroll bar is at the right so I just wanted to show you different ways you can manage gap between items and yes with that being said I think we are done with our flat list I'm going to check one Edge case when there will be an odd number of products for example if I comment out the previous this one I think yes the last one as you can see takes the whole amount of space because that's what we told him to do flx one is share the space equally amongst your C siblings but the last one doesn't have any siblings so it will take the whole space I think what we can do is probably add a Marx wh here of 50% and that will specify like take as much space as you need but not more than 50% and that will put the last one properly as well while we're still here I saw that the last image and maybe others as well is not fitting the container properly and that is coming from our product list item in the image by default images will resize to fill the whole container in which they are displayed and when the container has a different aspect ratio compared to the actual image that is being displayed sometimes we lose some of that image we can adjust that using the Reise mode and the one that is by default is cover which means cover the whole area with the image but when we are want to make sure that the whole image is visible we we can use a resize mode contain and look at the six cheese pizza it already fits fully and if I remove that it will be cut a little bit so in this situation I think we want a resis mode contain all right so that's it with our flat list that's how we use it to render lists of data multi columns how we use Gap to add spacing between items and yeah we are done with the menu screen and the flat at least all right now that we have uh the list of products in our application our next goal is going to be to create a separate screen for the details of one product so whenever we press on one of these items in this list I want us to navigate to a different screen with detailed information about the product so that's going to be our next lesson and here we have it during this lesson you're going to learn a lot about how to create screens using exper router how to work with Dynamic routes how to implement nested navigation and also how to understand the layout file in exper router we're also going to learn about stack and tab Navigators and how we can configure them to display exactly how and what we want so let's move on to the implementation details let's open our application folder the application folder as we remember is specific to Expo router and here is where all our screens are located the benefit is exper router is a file based navigation system which means that based on the files in folder structure exper router automatically creates and set up screens for us and the navigation between them so what do I mean by that for example if in our app directory I'm going to create a file called product. TSX in this file if I'm going to export a very default product details screen that will simply render a text that means that whenever we will navigate to our application SL product this screen will be rendered automatically without any extra requirements or without anything to do on the web that's very easy because we can literally change the puff the URL puff to go to the product on the mobile this will automatically become a deep link but about deep links uh we can talk a little bit later or the way to get on the product details screen is to navigate here how do we do that and where do we want to do that we will do that inside our component product list item because whenever we press on one of these component we want to navigate to The Details page linking between screens is done using the link component imported from export router what we can do with that is render a link link with go to details and provide the HRA property to the link which stands for the puff where we want to link to because we are using typescript it already recommends us some Puffs and we see the SL product which is our newly created screen in our app directory now we see that at the bottom of all the um product list items we see this link and if we press on it we are redirected automatically to this product detail screen so that's what it literally takes creating a file for our screen and then using a link or there is other ways as well using the router. push but yeah the easiest one is to use a link component to render basically a text link towards that screen but sometimes we want to wrap everything inside the component with this pressable link because right now only when pressing on the text itself will navigate so what we want to do is we want to wrap the whole component so let's copy this link put it at the top close it below the view and also make sure to remove this text because any text that is not inside the text component will raise this error text string must be rendered within a text very painful error when you first see it because it's very confusing but yeah so what do we see right now we see that first of all our styles are a bit uh broken because now the styles are on The View itself not on the link what we can do and what we should do is whenever we are wrapping around some other components of a vena text we can pass here to the link as child to make sure that the link is rendered as this view with its Styles so we see that the styles are back here now if we press you might expect uh it to work but it doesn't work and why it doesn't work well because a view does not have their own press event the requirement of a link is to use a child with a on press event for example the text has on press event so we could use a text as a child not a view what we can do is replace the view with another component from react native called pressible pressible is similar to a view but it has press events make sure to replace the root view with a pressable and the closing tag as well and that's it now the pressable has this on press event which will be used for the link and when we actually detect a press we are navigating to the product Details page that's the simplest way how we can implement this navigation between screens the next question is how do we know to which actual product are we navigating to well for that we have Dynamic routes with exper router and to define a dynamic route all we have to do is to define the variable that corresponds to that Dynamic part of our URL for example instead of product we will rename our file to the following syntax we're going to use the square bracket to specify the dynamic puff and then we're going to provide the name of that Dynamic variable in our case we can call it ID and that will represent presents the ID of a product that we want to render now if I'm going to press on something we're going to see a red error because we change the name of that screen back to our product list item we no longer have to navigate to/ product what we have to navigate is for example slash one for the product with id1 or slash two with product with id2 but in fact we want this to be a Dynamic Property taken from product. ID to add a JavaScript variable inside a a string we're going to use a template string with a back ticks instead of normal ticks and instead of a property that we want to replace with a variable we're going to add dollar sign curly brackets and then product. ID so what we are trying to do here is to navigate to slash then the product ID now if we check yes it works but we still have to receive this ID on the other end so let's go back to our ID to our product detail screen and in order to receive this Dynamic Property from our puff all we have to do is destructure it from the use local search programs which is a hook imported from Expo router and if I'm going to use it to render it here product details for ID and the actual ID when I'm going to press on the first one we see product details for ID 1 and I can probably product ID for ID one if I'm going to press press on the second one product details for id2 and so on until the last one so to recap in order to have a dynamic route with Dynamic puff parameters we add them inside the name of a file or the name of a folder that's also possible with the square bracket in our case the dynamic puff is the ID of a product that we want to render we take it using the used local search per Rams Hook from exper rout based on the same name so the ID here should match the ID from the name of the file and when we navigate we make sure to add that Dynamic Property um where we want to redirect to the next step is structuring and putting together our screens at the moment we see that our product detail screen inside is in our root Navigator is in our app directory that is our root Navigator and that means that this screen product detail screen is outside the tabs Navigator so when we go to that screen that's why we don't see the bottom tab Navigator because we are outside it what if we want to have a Details page of a product inside the tabs Navigator but not not as a separate tuab but as a separate screen from the menu tab for that let me first go ahead in our tabs layout and change a little bit the naming of our tabs if we scroll down here we're going to see tabs index with a title tab one let's change this to menu we will see at the top menu and the name of the screen in the bottom tabs is also menu for the T icon instead of code let's use Cutler okay that's good and let's also change the tab two the title from tab two to wers and here the icon from code to list now this is wers this is menu and it makes a little bit more sense when we will reference it I also want to reduce a little bit the size of this TB bar icon from 28 to maybe 20 yes now it looks a little bit better perfect so as I was saying back to our use case what I want to do is have a Details page as part of our menu tab that means that the menu tab will now not contain only one screen with a menu list but will contain two screens inside it a menu list and the detail screen that leads us to think that this is going to be a nested Navigator where we have a tabs Navigator first and inside it instead of our screen we're going to have another navigator that will contain the two screens that we need so how do we do that well first of all let's group these two screens that uh we talk about the menu screen with the menu list screen and the details of a product let's group them together inside a new folder that we will create in the tabs directory called menu I'm going to move a index TSX from tabs to menu and also the ID TSX which is our product detail screen I'm going to also move it to menu they belong together now uh the thing is that simply putting them inside the folder does not create an a nested navigator for that we have to include another layout inside this folder and that's how we group them together into a different navigator for example because at the moment even though they are in the menu tab they appear as separate pages in the bottom tab Navigator which is the parent the tabs so in order to avoid that what we are going to do is we're going to create a layout file inside our menu and _ layout. TSX a layout is the component that wraps around all the other child components from this group so the ID and the index will be wrapped inside the layout that's a good place to use for example data or context providers to give it to V screens or where we can Define our Navigators so let's do export default function menu which is going to be a function and to Define uh a stch navigator for this layout we can simply return the stack component imported from exper router and just like that we see that the menu in the bottom is one single tub if we go there we see a little bit like two two headers we can talk about that in a moment but if I'm going to press on this one we see that we are still here in the menu and and we can go back at the top so that means that now our menu uh tab in the tab bar is already not a single screen but an nested stack Navigator okay there are still a couple of things we have to to change for example in the layout of our tubs where we are accessing the index where we have this Cutlery we see that our menu tab lost the the tab bar icon because we change the name from index to menu here in our actual folder so let's change from index to menu here and now we see that back again here at the top what we can also do is if you refresh you'll see this screen doesn't exist why because we don't have any index screen inside our tubs and the index screen inside a folder is the default screen that will be rendered when that folder will be R will be be used in our navigation so what we will do is we will create back the index file inside our tubs index. TSX and I'm going to reuse this small redirect component from our guide that will simply return the redir component and what we see it doing is whenever we get on the index of our tubs we are simply going to redirect to the slash menu because that should be our home screen let's say so if I refresh we see that we land on the menu even though we see another added tab in the in the Navigator so it's a lot of going back and forth like you fix one problem now our home screen is the menu but we have this additional tab that we don't want to see in the bottom tab Navigator well that's not a problem when you know how to fix it and to do that in the layout let's go ahead and add a new tuab screen that will Target our index should be tubs screen we need to uh Target the index screen so by specifying the name index we can add configuration files so what I'm going to add is options H ra null and by doing that we are simply hiding it from the bottom tabs and it's not there anymore now I can refresh the application we land on the menu screen even though it's not the index we get here because we first go to the index and then we are redirected to the slash menu and in the slash menu we have that index of a menu with a list of products and our bottom Tabs are exactly what we want and probably the last step is to figure out this issue of double headers why it's happening well one header is coming from the tubs layout and if we look at the TBS with a name menu we see that it has a a header with a header even right with this icon and so on but the menu Tech Navigator has its own header below it before that we need to fix another issue when we click on the on an item we go to a screen that doesn't exist because we change a little bit the puth to our detail screen so we have to go to components product list item and when we navigate to our product the new puff is going to be menu I mean slash men / product ID yes as you can see it's working back and why how do we figure out the puth to a screen well we basically collect folders and file names until we get to that puff but the ones that are with round brackets these are optional puff parameters that's why we can either have tabs at the front and it will work exactly the same but because it's with round brackets this is an optional puff parameter so it can be skipped so the first one is stops then we have menu that's why we have SL men and then we have ID that's why we have product ID so it maps and it automatically goes here and I was saying that this Tech Navigator has its own navigation so what I'm going to do probably is the one from the tubs layout under the Tab screen with a name menu inside the options we can send here a header shown property false and by doing that we are basically hiding the header from the menu tab and we are left with only one of it that is coming from our menu stack okay we know how to hide it how do you change configurations to to screens well we already saw Here but let me show you in a very blank way for you to understand how we can do that so for example what I want to do is is change the titles of our index screen that renders the menu and the detail screen here how we can do that we can do that through the layout and through the navigation do screen for example stack do screen or tubs dot screen and so on by default if we don't provide any screens they will use the default configuration they will take the title for from the name of a file but if we want some additional configuration we can do that by moving from a first of all from a self closing tag of a stack to a opening and closing tag because in between the stack we want to have stack do screens because Expo router behind the scenes is using react navigation that means that we can use all the configurations that you know or that you can find in react navigation for example if you go to the configuring the header bar if we go here we will learn about like such options on the St screen that changes the title as I said because exper router is using R navigation we will be able to use the same options from react navigation going back here there are two steps to send options to our screens one of them is providing the name and this way we are targeting to what screen we want to change and it should exactly match the name of a screen here for example index so if we target the index we can send Now options and one of the options is the title that we can change to menu now the title of our index screen here became menu this is one way of doing it another way is directly not from a layout but directly from the from the page for example if we go to the ID page here what we can do is right away here use the same stack do screen that we saw previously and right away send options here like title details and if I go there we see title details the benefit of adjusting it like this is that we don't need to provide the name as it expor knows in which file you are calling this text screen so it will change the details of this one and another benefit is that here we have access to maybe variables like details plus ID so we see details one if we go to something else Details four it automatically changes the title of a screen based on information from the screen itself all right so that was more information about how to work with Expo router how to first of all create separate screens by simply creating files how to have Dynamic puff parameters that are sent through the puth to the component to the screen itself how we can have nested Navigators how we can have a stack Navigator inside the tab Navigator how to manage the headers not to uh override them how to also configure our stack Navigator tabs Navigator using options from react navigation and uh yeah how to to structure and use it in your application now uh we are ready to commit these changes and move on to the next lesson all right so now that we have our product details screen uh ready let's go ahead and actually Implement and render the details of a product on this screen for that in our next lesson product detail screen our goal is going to be to render the following screen a image on the top we're going to have a size selector and here we're going to learn about using state to manage the actively selected size price and at the bottom of the button to add to card okay let's go in our application and uh the first step that I want to do here on the product detail screen knowing the ID let's go ahead and get the actual data from our our products import products from our product array from the asset bundle and we're going to do that using product. find the product where product. ID is equal to id product. id let's do product. ID do2 string is equal to the ID that we get from the puff parameters for example the product with id4 in the following situation and having this product we can for example change the title to product. name let's see if that works we can go back select this product and the title of the page becomes the name of the product so that means that we are searching and finding the product correctly now we have these details but in order to avoid situations like this like product question mark. name which is a safe way to access the name on a product when the product can be undefined so sometimes you might have a situation when the product is not found so we can add a check here if is different than product simply return a text that will say product not found and now it's going to be safe to access it here because we know that we didn't stop here that means that the product is actually defined so it's safe to access its properties so what did we have there we had an image we already know how we to work with images so I'm not going to stop too much here let's provide the source of the image using the URI taken from product. image we can also have a default Pizza image imported from components product list item what's the problem here the image should be imported from react native perfect then we need to add some Styles well we don't have a Styles sheet yet so let's import the Styles sheet from Rec native and Define it here on the bottom const Styles equal Styles shit. create and here we're going to have all the styles for example the one for the container or the page then we're going to have the image so I'm going to Define some styles that I believe we will need initially empty but later we can add and style them what else the price we're going to have and for now probably that's it let's go ahead and uh give to that top view let's give style do container to the image let's give it styles do image and with this text instead of rendering this thing let's simply render the product do price and beforehand let's add a dollar sign to also render this on the screen for the style I'm going to remove this object and we're going to have styles. price if I open the page again we don't see the image we don't uh because we didn't provide the wi yet but if I'm going to add here with 100% or maybe it doesn't even have to be 100% or in the design that's what we have so we can keep it like this for the price we can use the same Styles as we had in other parts increase a bit the font size font weight bold and yeah that's good for now the container let's first of all say that we want the background color white now we see that the container stops where the items that we are rendering their finish if we want to say that hey container you should take actually the whole amount of space in this page we can use this Flex one property that will tell container to take all the available space now everything is wide behind the scenes that's good uh and we can add some spacing for this container as padding 10 to add some space space around it now it looks much better so that's our simple page with the image and the price our next step is going to be this select size component that will allow us to select different pizza sizes this is a very common feature on e-commerce applications where you have multiple options of products so uh here we're going to learn how we can do that for our pizza let's put it between the product price and the image and I'm going to start with a label text select size now we're going to have a couple of sizes like SML and XL we can render them as different text here like this SM and so on where we can dynamically Loop through the different options that are available and for every single option render something on the screen to do that first of all we need the the sizes where do we have them let's Define them at the top here const sizes equal to an array first size s then m l and Exel by having them in an array we can always come back and change them here without going through the code itself how do we render a list of items on the screen based on an array we saw how we can do that with flat list but a step behind flat list what we can do is use the JavaScript map operator that allows us to map an array of values from one form to a different form in our case we want to map from strings to something rendered on the screen to some GSX let's see how we can do that to start we need to access the sizes array here so that's why we need the portal with cly brackets then we're going to take the sizes and we're going to map through them in a map we we have a function that will be called for every single item in that array for example every single size in the sizes this function will be called and we need to return something the data in the changed form so what do we want to render for every single size we want to render a text component with the size as the value now if I go on this product detail page we see in a row SML and Exel and if I change something here it will automatically reflect on our screen perfect whenever we are mapping something to keep in mind of is that the items that are being mapped they should contain a unique key here this is important because that's how react optimizes how these components are rendered so the key should be unique so we can use some data from the item itself in our case we will simply use the size itself as the data some sometimes we use the ID when we have some objects or some other unique identifiers without that you're going to receive a warning okay perfect we need to put them first of all in the same row and to do that we need to wrap them around a view let's wrap the sizes map into a view with a style styles do sizes and the text itself we're going to wrap into another view to provide some styling for it as well like style do size let's close the view here and because now it's not the text who is the component being mapped it's the view we need to move the key from the text to the view itself and we're going to need also style for this size text so Styles size text let's go ahead and play a little bit with Styles we're going to have three Styles here Siz this we're going to have size for one item and we're going to have the size text for the text size text which one will I start with well with a size text I think it's simple we will increase the font size to 20 okay now we can see them better the font weight to either Bal or almost Bal like a 500 and yeah that's good in order to put them into the same line and not from new lines we're going to use the flex Direction on the parent component that's why we encapsulated them inside the view because if we assign to the sizes to this parent view the flex Direction row we are basically changing the direction of the Childs in that component so now all the Childs are rendered in the same row with a flex box we can also specify how they are sharing the space for using the justify content and initially that's Flex start but if we do space around the available space that is left will be shared around the items so this way we have little they they are spaced like they are spread apart now let's go ahead and uh style the size container itself I'll start with a background color a very light gray which is gains borrow and we see the the background being there uh let's go ahead and change the for example The Weave to something like 50 and maybe aspect ratio of one to make it Square to make it round we're going to use border radius and you should use like half of a wave or height for example 25 that will make it full rounded to align that text inside in the center we're going to use two properties one of them is align items Center that will put it on the center horizontally and justify content Center which will put it on the same horizontal line and yeah I think that's everything that I need here maybe the whole row of sizes can have some margin vertical to add some spacing there as well yeah that looks good so what we have right now is the list of sizes uh properly styled and rendered on the screen our next step how do we keep track of the currently active size what we have to for that is store somewhere which size is currently selected and based on that data display it or highlight it in this list that we are rendering here for example in the end result we want to highlight with a gray background only the item that is selected here is where State comes into play using State we can keep track of the data that changes in our component and based on it we need the component to re render to reflect it on the user interface so how do we keep track of State we are using a hook called use state from react use state from react an important rule of hooks is that they should be used in the body in the body of the component not outside not inside functions not even after if statements so try to always add the state and other hooks at the top of your component let's define our state by calling this hook and by also specifying the default value for example if we want the default value to be medium we can provide it here now the hook use State gives us back two things one of them is the value itself so let's call it selected size and the second one in this array is going to be the setter so we usually call it set and then the same name selected size whenever we have to update the value we will not be able to do that directly on the value we will have to call this Setter in order for react to properly update and reender our component so how do we use the selected size first of all let's use the selected size to conditionally render the background color of our size here here we're going to use a couple of Concepts like multiple Styles like conditional styles and state so let's take it step by step first of all what we want to do is we want to be able to change the background color right away here so the thing is that now all the styles of this view are inside the size which are here in the Styles shed and the problem is that we cannot send variables to the Styles shed what we can do is provide multiple styles to our component to do that we're going to put our existing style in an array like this and we can provide another object here for example background color red if I go there all the background colors are red why do we need the style here because whenever we have conditional Styles in this case we want the background color to be highlighted only for the selected size we can do that here with a conditional operation Operator by doing that if selected size from state is equal to the size that we are currently rendering question mark if that is true then the background color should be highlighted gains borrow with double dots we specify if this is false then the background color should be white and just like that we see that the m is highlighted because that's our default state if I'm going to select here Excel it's going to move there so that's how we conditionally Styles try yourself pause the video and try yourself to do the same for the styles of our text itself where the unselected is going to be displayed with gray and the selected is going to be displayed with black to do that we have to again put our existing Styles in an array and then provide the second conditional style I'm going to use the same structure as here because it has the same logic but this time the the color will change the color of the text so for this if selected is equal to this value the color will be black otherwise it going to be gray so now we see that the m is with black and valver is with gray perfect now how do we update which size is selected we want to do that when we press on our sizes so remember that the view does not have a one press event well for that reason we need to import a pressable that has the one press event we're going to go ahead and The View with style size we're going to replace it with a pressable and make sure that the closing tag is also pressable and now what we can do is have a on press event the onpress expects a function so let's add the function and what should we do when we press on this item we need to set it as the selected item so as I said updating a State variable should always happen through the setter through the set selected size for example so let's scroll down for the on press event and we're going to do set selected and here the size that we press on so now if I'm going to press on L we see that the selector changes right away and this way is how we can track state variables how we can update it and use it for for example conditional styles later on we're going to use this selected size when we submit the order and the last uh thing on our uh product Details page is the add to cart button for the add to cart button I have prepared for you the code for the button component which is going to be a reusable button component made out of a pressable with some predefined Styles let's go ahead and copy it from here and add it in our components new file button. TSX let's paste it and make sure that all the Imports are correct so real short this button is using a pressable component is basically sending all the properties that it receives down to the pressable including the on press and other properties and has some predefined style for the container and for that text that it displays to use this button component in our Details page page let's first import it so import button from add components it can also be like this now this button we can render it uh below the price with a text saying checkout or add to card right add to card now we can send to this button any property that we can send to a pressable for example on press and instead of specifying what should happen here we're going to call a function add to card let's copy the name of this function scroll up a bit and implement this function inside the body of our component because later we're going to have to do some logic here to actually add our product to card for now we can confirm that everything works by doing console war adding to card and if I'm going to go to this page and press add to card we see a warning at the bottom adding to cart which is is coming from here and in this add to card function we will also have access to the size that the user selected by accessing the state variable so if I select small pizza I will see adding to card size s and if I change it it updates perfect now think that we can do is simply putting a margin Top Auto to our price it will move the button and the price all the way to the bottom of the screen for easier access to to the to card button and with that being done we are finished with our product Details page let's go ahead and add all the changes to our repository product details screen so far we have our menu screen and the details page of one product where we can select different sizes what we want to do next is to implement the card features so whenever we press on this button add to cart we actually actually want to store it somewhere in our application and we will need a card screen as well from where we will see all the items that we have in cart and later be able to check out so in the next lesson we're going to implement the shopping cart which is a very common feature in a lot of e-commerce applications and it's a great uh use case to teach some of the react context and how to have share data in your application so in this lesson you'll learn how to use models we're going to use use a model for the screen that will display the card we're going to learn how to use react context to share data across components later we're going to implement the shopping cart features like adding to card like counting the totals and so on and we are going to implement that in our application so let's go ahead and start by defining the structure and the screens that we need for our card as I said we want to render a cart as a model and we already have an example of a model here actually it's nothing special about the model itself so we are going to Simply call it a card. TSX let's render something dummy here basically the card screen export card screen and we need to navigate to this uh screen when well let's use a header button with a card and that way when we press on that icon to open the screen we saw that functionality is inside tabs layout for the menu and even though at the moment it has header shown false like if we comment down we will see this menu with a icon that opens the model so I purposely didn't delete this header right for us to take inspiration from here what we want to do is to add the same icon but on the header below which belongs to our menu layout so in this menual layout what we can do is using screen options on the stack we can assign the same options to all the screens inside this tack one of these options is going to be header right and using header right uh we can render something in the right part of a header if we go back to tabs layout we see that that menu is using uh header like with a link to a model so let's basically copy everything from here we can even copy the header right like this and move it to manual like out as the header right like this here we're going to need to import the link from export router the pressable from react native font awesome from Expo Vector icons colors from constants colors and I don't need the color scheme I can do colors do light tint and if I do light tint we see that the icon below is with blue now to not forget let's let's go back to tabs layout and hide this header that was hidden before now that we don't need the header right anymore on our tubs menu we can remove it from here because we moved it to our menu stack Navigator let's go to the menu layout and finish some of the things that we need here for example what should uh the puff B when we press on this item it should be slash card because that's the file or that's the screen that we Define card so if I do card it's going to redirect to the card now I want to also change the the name of the icon or the icon itself to shopping card okay perfect so now the icon is correct and it redirects to the right screen but as you remember we said that we want that screen to show as a model how do we do that we can have a look at how the previous model was configured and to do that let's open up root layout and you're going to see that there is a stack screen model that has an option presentation presentation model and that what makes that screen show as a model so let's actually change from model to card here presentation we will leave it as model and now the card displays from the bottom as a model perfect and one more thing is that we don't need the model anymore a cool thing in the model that we can still look at is the model changing the status bar color the problem is that now with a card when I open the card you see that we don't see the time and the battery anymore because they are rendered with black on black that's why using the status bar from model TSX we can use it in card to adjust the status bar style status bar what's the problem is it imported from somewhere else stat yes it's imported from Expo status bar so make sure that we don't import it from react native but from Expo status bar and now when we open the card battery and so on will be displayed with light because that's what we have here if it's iOS and we are on the car screen display the status bar with light colors okay now I think we are safe to remove a model we don't need it anymore we're going to focus on our card and as you can see this uh header right is available on the product Details page as well so it's accessible really easily from multiple screens the next step is about our react context why do we need a context and why state is not enough the problem is that the data of items that are added to the card should be accessible from different parts of application for example to add things to the card we're going to have to do that on the product Details page when we press add to cart item and to see the items in the cart we're going to do that inside the card screen if we want to do that with simple State we will end up with a problem called prop drilling where we pass a prop down to a lot of children like from up component to the screen from the screen to the list from the list to the component and so on so if even though it will work uh it will be very hard to maintain such an application that has this prop drilling instead of that we're going to use react context that allows us to provide values or data to other components in our application so first of all let's see the basic structure of a context provider for that I usually like to keep uh the providers in a separate folder called provider and let's start by defining our card provider. TSX in a context provider first of all we need to create the context that is done uh card context using a function important from react called create context and the value of a context let's initialize it with an empty object in a moment we're going to add some values in the context that we need to share now this card context is an object with two properties one of them is card context. provid and one of them is consumer a card context. provider is used to provide values and card context. consumer is used to get or to consume these values so let's first use the provider and we're going to use that in a custom component here called let's call it const card provider this is going to be a component that will render the provider card context. provider the provider needs the value which will be the value that we export basically that we make available to the card context consumer values here can be for example items which is an empty array initially and maybe on add item which is going to be an empty function or a function yeah it can be values it can be functions anything now all the children everything that is going to be rendered inside the provider will be able to consume these values so for that reason we're going to use this card contact card provider to wrap around the whole application we're going to receive the children here which in a moment I'm going to show you what is this children and we are going to render it inside our context provider that means that all the children of our card provider will have access to the card context to the react context which is called card now let's use our newly created component card provider but for that I'm going to need to export default card provider so let's use it to wrap around our screens that needs this provider what I'm going to do is I'm going to wrap around all the screens in our application that is uh going to happen in the root layout upore layout is a file that will basically be available and wrap around all the screens in our application so what we have to do here is import card provider component from providers card provider and let's scroll down where until we see the root layout navigation and wrap around Our Roots Tech Navigator here our newly created card provider component let's figure out what's this children this children is the structure from our properties because we remember the first parameter are the props and we also remember that a property with the name children for example should be passed to our component as for example children and something right well that's not the case for specifically children component this is a special property the value of the children property is going to be everything inside our opening and closing tags so between card provider opening and car provider closing tag everything here is the children so think about copying this tag from here and replacing it here that's what happens behind the scenes and that means that now all the stacks in our tubs in our cart and in other components we will have access to the items and the value that we export here but that is happening behind the scenes and we are simply taking the children and rendering it inside our context provider just with this setup we are providing uh data as I said there is also another component card context. consumer however we are not using it very often because it's much easier to consume a context using a hook called use context and by using this cook use context and the actual context we can get the data from this context in other components that has access to it so let's go ahead and first do export const card context and let's see for example inside the cart let's go ahead and consume this context and get the items so inside the cart we need to consume the context as I said for that we need the use context Hook from react and the actual context that we want to consume called cart context from cart Provider from providers card provider now this use context is a hook so remember it should be somewhere at the top of your component we can get access using use context and sending the card context inside this we will get access to the values that we make available for example items so let's take items and and let's do here uh card items length is equal to items do length now if I'm going to open my card we see that card items length is zero but from the card provider if I'm going to export an array with I don't know one two three we're going to see that the cart has the cart items left free so that means that from our card screen we can get access to the data from our card context by simply using the use context hook and passing the actual context here and also making sure that the screen where we take this is somewhere inside the provider and because we wrapped our whole application in the provider we are sure that the data is available everywhere another cool trick that I want to show you here that will help you avoid having to import two things every time you need to use this context and the things are used cont context and card context is in card provider to create a Shand that will put them together we're going to do that by exporting a custom build hook which we will name it use and something like card this is going to be equal to a function that we'll call use context and we'll specify card context now we don't even need to export this context anymore because if we want to use it we can simply import use card use card and instead of use context card context we can do use card now I can remove the card context and the use context and with a simple import we have the same functionality because we created this useful uh Shand towards using our card context so yeah this is going to be your example or template of uh context whenever you will have to work with one so first we create the context using Create context from react then we use the context. provider to wrap around children to wrap around other components then we make sure to use the provider and wrap around the components or screens that needs the data if only a couple of screens require that data maybe you can put it around them only after that we defined a custom hook to get get access to the context using the use context and anywhere we import the custom hook and we get access to the items or to the data now before moving forward as you can see first of all let's fix some typescript issue this children is not typed and we can use a helper type imported from react called props with children and this prop with children will have a proper typing for a children component another problem is that if we look into the cart. TSX when we use the cart it says that I don't know about any items that's because we didn't specify what type should our context be first of all let's create the type for card type and what should the card have first of all items which is going to be an array of something that something is an array of card items and as you can see a cart item will contain uh information about the product it will also contain the quantity and the other options like the size so when an item when a product is added to the card we need to know what product is added how many of them are added and what specific options were selected that's our defined type here so in the card provider let's say that the items will be imported from our types and it's going to be an array of them and the add item is going to be a function that will receive a new item of type cart item it will do something and give us back nothing like void no actually we're going to simplify it a bit instead of sending the item we're going to send the product that we want to add to the to the store using the product type and what else like the the the options that we want for example a size the size we can specify it as cart item and select specifically the size property so the size should be cart item at size which will take the pizza size from here okay so let's Implement these items and add item inside our card provider here in the C provider we can use State because now the state is made available through the context provider so we will keep track of all the items in our card in a state variable here so let's define it as items and set items use State initially it's an empty array we can specify also the type of the state like what data do we want to to hold here as card item array now the items that we expose for the provider will be the ones coming from the state so I'm going to Simply remove the dami array from here and pass items here and whenever you have the value the name and the value in a object similar you can simplify it by removing it and it's going to be the same on add item uh it's going to contain some logic so let's uh create a function out of it add item the add item remember it's going to have V structure it's going to receive a product a size and it should do something with it now let's map it to this OD item that is exactly what we have here oh but we forgot to save it the car context is of car type to do that with angle brackets in the create context we can specify the type it will complain that the initial value doesn't have uh the required shape but we can fix that by adding some default values like items is empty by default and add item is an empty function by default these are never going to be used because they will be overwritten with the actual value implementation in the provider value adding the item let's first of all console log product here and think about where should we call this add item well we should do that from the product Details page when we press on the ad to cart button let's go ahead into the tabs menu ID this is our product Details page let's import the use card and let's get access to the add item function from use card if we hover over the add item it should specify the add item is a function and it expects a product and the size that's good because we have information about the product on this page and we have information about the selected size in the state so when we press on the button we call this function add to card what we want to do here is simply call add item which is the function imported from our react context provide here the product and the size for the second one selected size we see that the product here can be undefined whenever it's not found so we can add a simple check here if product is undefined then return basically don't do anything now the second option here is that selected size argument of type string is not assignable to parameter of type Pizza size because our state is a simple string but we need it to be of type Pizza size imported from our types it might also have some problems here with set selected because this array of sizes that we are using is an array of strings if we want to specify that it's actually an array of pizza sizes we need to tell it in the definition and now if you're going to do some mistakes here it's going to say hey this is not a pizza size and everything else is completely type save so let's open the terminal and see what do we get there when we press on a to card we basically see the product and also we should see the the size as well what we can do with this is we can create a new uh card item of type card item and what Fields does it need it it needs the product that we can take from the variable that we receive it needs the size if we look at the card item it needs product it needs size it needs quantity quantity let's start with one I think it also needs product ID so the product ID maybe now it doesn't need but later on it will need because that's how we will connect it in the database and another thing that it needs is an ID based on an ID we're going to be able to change and update later on the quantity of that so if I do here ID one it should be a string id1 now we don't have any errors and what we can do with this new cart item is appended to the rest of the items from our estate to do that what we're going to do is call the set items and we're going to set it with a new array made out of first of all the new cart item at the top and then the rest of the items that already exists in our state we do that by destructuring the arrays or spreading sorry now if I'm going to go ahead and for example add this pizza to the card and go to the cart we see cart items length one if I'm going to press again we're going to see cart items length two and we can also have a look at the items themselves using a simple console log in a moment we're going to render them but until then let's see if everything is working properly initially it's an empty array if if I add ultimate pepperoni size medium there we see that the ID one product we see the quantity we see the size M if I'm going to add another one with a different size we see that this array has already two objects let's leave a couple of Tod do here not to forget and move on on to rendering the current because it's going to make more sense if we see something visually and then come back and add the rest of the features here for example when adding an item if already in cart increment quantity then the ID shouldn't be hardcoded the ID should be uh generated so we're going to do that as well and of course we're going to add some other functions like update quantity and so on that's going to come in a moment but as I said let's go ahead and on the card let's do something with these items from the card so if I'm going to open card. TSX we already import the items what we have to do is to render them so having an an array of card items we're going to use a flat list here inside of this text we're going to use a flat list imported from react native where the data is going to be the items imported from our cart and the render item is going to be a custom component for the cart list item we can reuse use the code from here to save some time and focus on the functionality so let's copy the code that is responsible for rendering one card list item we're going to look at how how everything happens but it's nothing new nothing more than we already saw today let's copy this one and inside our components let's create a new file card list item. TSX let's paste the code let's go go at the top and make sure that some of these URLs are correct for example the constant images is not there because with default Pizza should be imported from somewhere else default Pizza should be imported from product list item there is no update quantity yet so I'm going to delete that from here and we can comment out the on press event here and the rest should work as expected now let's use this car list item render it and then we're going to come back to see some implementation details back in our car. ttsx in a flat list where we have render item let's take the item and render it using the imported card list item card item item just like that now it doesn't display anything but if I'm going to add for example ultimate pepperoni to the cart and if I'm going to open it it's already ve and if we go ahead and add a large margarita it's going to be ve as well let's go ahead and add some content container style to our flat list to add first of all some pading and some gap between the items that's much better and as you as we can see we can look at the cart list item and what it renders here is it starts with the image of the product then it has in the middle the name of a product the price of a product and the size that was selected we see that the pepperon is M the margarita is L then it has the quantity selector on the right which in the middle displays the current quantity from the cart item from the data that we store in the global context and two icons that will help us change the quantity based on the cart item id we're going to implement that in a moment so yeah now now our card is going to look better and I think we can also navigate there whenever we press on the ad to card so in the app tabs menu ID when we add to cart I want to navigate to the shopping cart we saw previously how we can navigate using links but a link will not help us when we want to render it programmatically from some functions to redirect in that case we will use the router that we can get access to by using use router hook imported from export router then for example in the add to card after actually adding the item to card we can do router. push and we can push to the cart now after pressing on the add to card the cart will open up the next feature Let's uh go back to our card provider and Implement some logic and additional functionalities around this card provider one issue is that whenever we add the same item multiple times it adds its individual card items maybe that's what you want but I thought that it would be useful if we simply merge together uh card items and simply increment the quantity If the product and the size and the options are the same so how can we do that whenever we are trying to add an item let's check if the item is already in the card simply increment the quantity but for that we we we could reuse a function called update quantity but for updating the quantity our card items should have unique IDs the problem is that at the moment all of them have the ID one and it will also generate an error here encountered to children with the same key one because the ID is used for the key inside this flat list what we want to do is to generate a unique ID for every card item the way to do it is using Expo crypto and Expo crypto has a function called generate U ID that allows us to generate a random uh unique ID to use uh Expo crypto let's go ahead and install it from the documentation in our application npx Expo install Expo crypto then we're going to import in the car Provider from Expo crypto let's import word random uu ID like this this is a function and when we call it it generates a random string for the ID so we can replace this hardcoded one with random uuid now our items when we add them to card they will have a random idea and I'm not sure if we display it somewhere we can I don't know console log them here console log items and we're going to see a random generated ID the ID looks like this this a random string perfect and basically when we cre add a new one it's going to have unique IDs and because they will have unique IDs we will be able to change the quantity of a card item knowing its ID so let's add a new function to our card context called update quantity I'm going to start from the top by adding it to the type and let's call it update quantity quantity what it will need is the card Item ID or item id of type string and the amount that we want to update the quantity with it can be a number but sometimes you don't want to let uh the quantity be updated with any kind of number sometimes you want only to do minus one or + one so you can specify that exactly here by providing literals as a type and this is a war so it's either minus one or one will be accepted for the amount the answer the return is going to be void we don't expect anything back the update quantity let's make it as a empty function in the default when we create the context and lastly we need to implement it here let's copy the definition from the top from the type let's add it as a function in our body as const update quantity to this and instead of voice let's add the body of our function and we see that the value mentions that we haven't provided the update quantity function to our context provider yet now that we have added it let's do console log Item ID and then amount we're going to think about the implementation in a moment now I want to link this update quantity function to the plus and minus buttons to do that let's go ahead in our components cart list item where we render the plus and minus here first step is to use the use card and get access to the update quantity function and because our uh Expo Vector icons they have this on press event we can simply call the update quantity with a card Item ID and for the minus we will use the amount minus one and for the plus we're going to use the amount simply one and by doing that we're going to see in the logs when we press on plus the ID of item and one and if we plus minus is going to be the ID and minus now how do I actually update the quantity so what we are interested in is to first of all find the object with that ID that we specified and update the quantity V so situations like this are a bit challenging uh when working with a state but in this case we're going to use some array methods to Loop and map around our objects and change it exactly how we want what do I mean by that let's do const updated items equal to is going to be equal to items but not simply items we want to map through these items and whenever we map through items what we want to do is to basically change the shape or or change the individual items in that array the thing is that we don't want to change all the items right we want to change only the one that matches this ID so what we should do is first of all check if item. ID if it's different than the item ID that we are trying to update then we don't want to do any changes to it so I'm going to Simply return item otherwise we're going to return an object with some Fields changed What fields well we don't want to overwrite the rest of the fields so we're going to destructure everything that already exist in that item and we want to Simply change the quantity to item do quantity plus the amount that we want to change it with now these updated items will contain the same items only one item with that ID will be changed the quantity of it will be changed we can set it back to our State as updated items now if we have two items here one pepperoni and one Margarita changing the margarita plus one changes exactly event minus one okay works this one works and this one works I know this can look a little bit intimidating and I will even go one step forther to not use a intermediate updated items but to put it right away here it looks a bit intimidating but using a map we are looping through every single item we are checking if it's not the one that we are interested in don't do anything with it simply give it back and put it back in the array however in the other case which means that if the item is the has the ID that we are looking for for that one we need to update it so create a new object with all the fields that currently are in the item such as the size the product product ID and only overwrite the quantity field of that item using the existing quantity of the item plus the amount so here is quantity either minus one or + one so that's how we update the quantity it works and it should probably work for yeah it will go in minus as well so shall we think about something here yes what we can do is after mapping and updating the items we can put another step to this array of filtering and filtering is basically getting rid of some items from the array so filtering we're going to go through the item and we're going to filter only if item do quantity we're going to keep the item in the array only if quantity is more than zero so now after changing the shape with mapping for example here after changing the shape yeah we see that as soon as it reaches zero it will remove it from the card perfect now uh we could we can reuse this update quantity function in the add item and check if the uh item that we want to add to cart already exists there for example if pepperoni with size M already exist here the second time if I press instead of duplicating it let's simply increase the quantity of the first one so how do we do that first of all we can take the existing item by finding or by looping through all the existing items in our state and finding the item that matches our condition when should we consider two cart items the same whenever the item. product is equal to the product and also when the size or the other options are the same not only the product should match but also the item Dot size equal to size now if it finds one of these items in our array if existing item then simply call update quantity to existing items. ID and plus one and stop here add a return statement to stop the execution here and not add a new one let's have a look if it works if I'm going to go to Ultimate pepperoni if I add once it's one if I press add to card again it's two if I change the size it's going to add separately as one because it's a different option if I'm going to do again it's going to increase that one if I go back to M it's going to increase this one if I'm going to completely change another one another Pizza it's going to add it separately so as you can see it works properly okay perfect and I think with that being said we are done here let me remove this console log from here this one was quite a long task but we learned a lot uh implementing it I think there is also some additional things in the curent uh screen that I wanted to add for example I wanted to add at the bottom of a screen a button so button with a text checkout okay and maybe also the total price of our card and I'm going to do that but before I'm going to add some putting to the whole page not only to the flat list to have it here as well yeah as I was saying there is uh in a lot of cases the situation where we want to uh show the total value of the items in the card to do that we're going to keep the logic of calculating this inside the card provider because yes we can import the items here and calculate it here but what if we need that information in multiple places we're going to have to copy paste the same logic multiple times but if we keep the data here in car provider it's going to be easier to get access to it so for example we can have a value here total which is a number number the default value of the total is going to be zero and let's calculate it well before calculating it let's simply do total here yeah we actually need con total equal 1 2 3 we're going to come back to to implement the logic of calculating the total but let's go to the cart itself and from the use card let's import the total value we can render it above a checkout button as a text saying total dollar sign and then value of this field so now if I'm going to add something we see total and V one can add some style here margin top 10 or even 20 font size 20 and font weight we can do something like 500 now uh that we are rendering it we can go back to the car provider and let's calculate the total of all the items how do we do that there is a function on arrays in JavaScript called reduce the reduce will Loop through all the items and will collect all of them in one single value it is very useful for calculating for example averages or sum or products and so on the way reduce works is it will call a function with two things one is going to be the value that we accumulate over the execution of every iteration in our case let's call it sum because we want to calculate the sum of the value of all the items the second value is the current item that we are looping through what we want to do is we want to add to the sum for example item do product do price and you also need to provide the initial value at the end as zero because initially the sum will be zero so if I'm going to add a pepperoni here we're going to see the total s the total change if I'm going to add another Pizza the total calculates automatically but if I'm going to change the quantity it doesn't update the total because we are simply gotting the item do price what we actually want to do is to add item. product. price multiplied by item. quantity and this way when we increase the quantity of item the total will also change automatically and just like that uh we calculated the total amount that the user will pay by summing the value of all the items in the card let's go ahead and do get ad and now we are definitely finished with our shopping cart all right so what we have so far we have our product list page we have a product Details page we are able to cre add things to our card we are able to check things in our card update them manage everything and the next step is going to be whenever you press on the checkout what we want to do is to take this card and create an order out of it we're going to do that in the next module creating and saving the order in the database based on the information from the card but after that what we will do is we will redirect the user to the order Details page everything related to the orders is going to be an assignment at the end of this module for you to practice and try to implement uh things that you have learned so far I'm going to provide more information about the wers uh assignment later but now let's think about the next steps once we will have a wers implemented our application for the user side will be more or less complete the users will be able to view items manage their card create orders and manage their orders that's the most important part of a e-commerce application or a food delivering application in this use case now let's move on to the other side of application the one that is going to be used by the administrators or the people who will manage the restaurant because that that side of application will have a little bit different features features yes it will also allow uh the administrator to view a list of products to view a list of orders but it will also give them some extra features like creating a product updating a an ARD being able to filter between wers which are active and archived with that being said let's go ahead and move to the next task which is going to be our admin side the admin side is going to be the part of our application that is going to be us used by the administrators so because it will have a lot of common features with the users the plan is as following we rename the tabs folder to user to specify that this bottom Tabs are for the user side screens we create a new group admin and we basically have all the other screens that are the same between user and the admin we then create additional screens for the admin inside like creating a product updating it and so on and then at the moment in development mode we can switch between user and admin side and later on uh in the course we're going to see how that can be automated based on the user information and the user group that it belongs to that is going to come with the authentication but for now let's make sure to structure our application with all the screens for the user side and the admin side okay so I'm going to start with probably naming that tubs to user this way it's going to be clear that this is the user side screens or user related screens let's go to the layout and make sure that we rename here from tubs to user as well and reload the application everything is working as it was working before perfect that's good now let's go ahead and copy paste the user folder and let's re name it to admin how will we differentiate if we are on the user or admin we will do that by opening admin layout and in the tabs screen options let's do here uh tab bar background it's going to be colors. light. tint hm background uh tab bar style yes that's what I wanted and it's should be background colors light like this so if the background color of our bottom tab is going to be blue that means that we are on the admin side so far it's with white which gives the impression that we are on the user side if I refresh we are on the admin because uh admin is alphabetically before user so that's what why it chooses admin by default and there is some issues with the bottom tabs as well so while we're we here let's fix it for example for the top bar active color I'm going to use here colors light dot not tint but background because we switched them around so now tab bar inactive tint color can it be lighter yes I think that one is good so now we are on the admin side let's go ahead and hide the header here and we're going to do that in the layout in the root layout the same way as we hide the header of a user TBS let's duplicate this and rename one to admin and also have header shown false now we got rid of a header Veer how do we make sure that at this moment we are able to navigate between user side and admin side for that we're going to add a root index file that will be the first screen that will be rendered and let's use this simple component that has two buttons to admin and user that will help us do this navigation now if I reload the application we are greeted with the index file this is again temporary until we implement this automatically to be redirected but we can press on the user and we are redirected back to the admin I think if I go to the admin we are here if I press user we are also there you know why because in the user index. TSX we have this redir to the menu and because it doesn't specify in which menu is it admin menu or user menu it's going to go to the admin menu so let's go ahead and add the optional uh puff here to go to the user menu from our app user index we are redirected to the user menu and from our app admin menu we are redirecting to the admin menu this way if I'm going to refresh press on the user we are on the user side we know that because the bottom tab bar is with white and if I refresh again and press on the admin we are redirected to the admin side this navigation is very important uh for us to understand because at this moment we have in a way duplicated Puffs because the slash menu for example or slash2 is available both in the admin and and in the user side application so it's very important for us to navigate to the right side and later on we're going to add some automatic rules to avoid uh user getting on the admin screens we're going to do that don't don't worry but for now let's go ahead and make sure that for example when we press on the item on product item we are redirected correctly from the admin screen but what happens if I'm going to go to the user screen and press on this item we're going to go be redirected to the admin side so for that the same reason as we have to add this prefix admin on or user we're going to go into our components and change the product list item because we need to be clear to which menu item to the admin or to the user but how do we know where are we currently like on what screen we are currently at we can know that using the either puff name or the segments puff way will give us the whole puff where we are and the segments will be split by V slash and if I do here console log segments and open it up we're going to see that the segment is an array where the first part is the folder admin then menu then ID I'm going to refresh go to the user you're going to see that the segment at the beginning is user so what we can do is using this segments the first element from the segments we can prefix our link with it here slash and then segments at position zero this way if we click on a product item from the user side we're going to be redirected to the user side menu product details and if we are going to refresh and go to the admin side and click on it we're going to go there because the segments will specify exactly go to the menu under the current segment that you are at this should have been done uh easier this should have been a simple relative puff but at this moment I didn't find it working properly and a relative puff should automatically do that for us but it doesn't work that's why the work around is reading the segments and using it when we navigate to some detail screen okay so that is our basic structure of the admin side with the basic screens that are basically shared among user and admin here as an admin the similar way as a user what we can do is see a list of menu items I don't think we need the card here so what I'm going to do in the admin menu let's go to the layout and here in the header right we're not going to have a card but you know what we're going to have we're going to have a way to add new item so let's add a plus here or plus square- o that will be plus like this and what it will do it will redirect to the create screen at the moment it doesn't have it so later on we're going to redirect here to the create product screen but for now we simply have the ey conveyor and I think it's not going to be on all the screens I think it's going to be only on the in index on the home screen that renders a list of items so let's take the header right from here and add it to the options of the index screen and just like that the details page will not have a header right only the index will have I can safely remove the screen options from here and while we're still here we can also add another icon on the details page so let's go ahead and copy paste this text screen that already has the header right with icon as an example and instead of name index let's target The Details page it has the name ID with square brackets so the icon that I want to render on the details page is added so I think there is an icon pencil that when we will press will redirect us to the edit screen while we are still hear the details page of the menu item for the ad admin it will not have the size selector we don't need that so I'm going to remove everything that has to do with sizes so I'm going to highlight The View with style sizes going to scroll down and remove everything here same way with select size add to card I don't think we will need add to card the price doesn't need the margin Top Auto we can also remove some styles for this side yeah we can leave only the image probably the title can be rendered besides the price here it depends on you like how you want to structure and display it title oh let's uh so the title can be I don't know 20 so the details page is not that important here the admin will be able however to go to edit the product we're going to implement that in a moment from wers you're going to implement that as assignment and yeah I think that's the most important part here so that uh the structure of our admin side screens is complete so I can go ahead and do git add get commit admin side the next task is going to be the create a product screen in this lesson you're going to learn uh how to work with text inputs how to build simple forms in react native how to add input validation and also how to work with image Pickers by the end the goal is to create the screen like this that will allow an admin to create a product by selecting the an image by providing the name price and a button to create the word so let's go ahead and start implementing this uh new screen for creating a product so in the menu on the admin side besides the index and the details screen we're going to also have a cre create. TSX screen let's initialize it with a empty component like this create product screen and knowing this we can in the layout where we have this plus Square in the admin where we have this plus Square we can link to admin SL menu slash create now if I press on this plus sign we are redirected to our create screen so what do we have to do here let's start by defining the Styles shet and we're going to have a style for our container and later we're going to add something else let's start by styling this container I want to align everything in the middle so to do that we're going to use a flex one to make sure that our page expands the whole screen we're going to use a line items Center actually I don't want to align them vertically in the middle I want horizontal so I'm going to use justify content Center and maybe some podding like 10 now the next step is to start working with uh to create our form as we can see here the form will contain two input boxes one for the name and one for the price let's go ahead and see how we can work with uh text inputs and how we can build simple forms to work with a text input we have a built-in component in react native called text input to render it on the screen uh I'm going to render it B below this text as a text input it's a self-closing tag and we will not see it on the screen but it's there if we add a placeholder here name we're going to see the placeholder on the screen and we can start typing okay that's good uh let's go ahead and work a little bit on the style and after that we're going to work on the logic and how to keep track of a data so for the Styles I'm going to do style. input and a above a style let's use this text as a label so it's going to be styles do label okay let's go ahead and add this input and label Styles in our Styles shet and go ahead and start styling it for the input I'm going to start with a background color white that adds it there I'm going to add some poding to make sure that there is some room like some space to breath I'm going to make sure that the corners are a bit rounded order radius 10 maybe it's too much yeah five is okay and you can also work with for example uh borders I'm going to add some margin top five and some margin bottom more in order to separate two different inputs from one and each other for the label what I want to do is just simply decrease the importance of it by saying that the color should not be like a black but a gray like like this maybe font size a bit larger like 16 yeah maybe that's good so with Styles I think we are good what I can do is I can duplicate this to have our price the place Holder will be 9 99 and in the label I can also specify the value now everything should work but there is also a way to adjust what kind of keyboard should the feel provide for example to enable the keyboard on the simulator I'm going to press command K and we see that both of them are rendering a text keyboard if for the second one I'm going to say keyboard type numeric we're going to see that the first one is normal uh letters and the second one is only numbers and we can specify the price this way it doesn't mean that it's actually a valid number because we can with my keyboard I can write V letters as well it only specifies what keyboard type should be used perfect uh what else do we need on this screen well we need a button so let's use our reusable button component with a text create and the function on press we should call the on create function that we can Define here oncreate creating product at the moment we're not going to do anything in this on create but later in that tutorial in the course you're going to learn how to save information about the product in our database however at this moment we need to make sure that whenever that will happen we will have access to the actual values that the user writes here because at this moment when we press on this button how do we take the value that the user wrote in the text input well at this moment we cannot because these are uncontrolled inputs meaning that they are managing their own data behind the scenes what we can do is make them a controlled input to do that we need a state variable for example for the name and set name is use State initially it's going to be empty string let's do that for the price as well use State and the state uh of price is also going to be a string and later we're going to convert it to a number to make a text input a controlled input we need to um bind the our state variable two ways one way is by sending the value the name that means that whatever the State field has it will display in the text input but at this moment if we try to change it will go back to what's in the state because we are never updating the state variable that's the second way the second bind which is when the text changes on change text we want to call the set name with a new value so now I can write something here and I will have access to it whenever we press on a button by using the state variable so we you're going to see the value of the name we can do the same for our price by sending the the state to the value price and the setter to the onchange text set price now we can handle the price as well and probably there will also be a reset fields function that will reset the name to an empty string and we reset the price to an empty string and we can call that after we successfully save our values to to the database save in the database that's coming later now if I'm going to press create it's going to reset the fields there regarding input validation there are very good libraries that helps us do that but I didn't want want to include them here in order to keep this uh tutorial simple and accessible to everyone so I'm going to show you how we can add custom input validation with some checks and some functions that we can create that will add at least some basic validation to our forums so first of all let's go ahead and above the on create function let's create another function called validate input validating this function will go ahead and validate all the fields that we have and if there is an error it will set it in state in order for us to display it on the screen so let's go ahead and create the errors and set errors state which is going to be a string now in the validate input let's go step by step and validate our fields for example starting with a name if there is no name I want to set the errors to name is required and I will return false meaning that some inputs are not valid we can do the same with a price if price is not defined I will set errors to price is required and return Falls you might also have some some more complex validation fields for example for us it's important that the price we will be able to pass it to a number so what we can do is we can check if parsing the price to a float number number if it gives a not a number is none if parsing the price results in a not a number that means there is a some characters in our price is not is not a number and we can return false and if none of the if statement returned or none of the if statements were true at the end we can be sure that all the fields are valid based on our rules and we can return through now inside the oncreate before we save in the database what we want to do is to validate the fields so we're going to check if validate input is false is different than validate input because it will return false when there is errors we're going to say return here don't go however if the validate input return true it's going to make sure to submit the data to the database now what we can do is Maybe above button display our errors to make sure that we know the errors and we can also add some style color red now we don't have any errors but if I'm going to press create we see name is required I'm going to put the name we see price is required if I do a AA create price is not a number so only having a proper number will work and we also need to make sure that when we call validate input let's start by resetting the errors because we see there ER are not reset name is required and here if I do 1 2 3.5 create it works perfect so that's our basic input validation The Next Step uh on our form on our create product page is going to be to select an image so let's first of all start by rendering an image above our inputs to do that I'm going to use the image for the source let's start by r ing the default Pizza image and for the style it's going to have styles. image we have to import the image from react native and Define some styles for this image we can make it half with so with 50% and aspect ratio one now if I'm going to go here we should see the image here we can also work with align self Center to self align the image in the center perfect below the image we're going to have a text saying select image that will allow the user to select a new image from his camera roll let's add some styles to this one as well and let's call it styles. text button text button what does it need it needs first of all aine self Center it needs font weight bold and probably color colors like do tint select image perfect maybe some margin vertical to add some spacing around the text button perfect so the next step is going to be to actually allow the user to select an image from his camera rooll for that we're going to use a package Expo image picker the Expo image picker is a library developed by Expo that allows us to select images from the gallery in order to install it let's start with npx Expo install Expo image picker I'm going to open the terminal and install it here then let's have a look at the example that they provide if we scroll down a bit here is the usage what we need is a first of all a state variable where we will store the URI of the image so let's copy this state variable and add it at the top of our file now there is this pick image function that we can look in a moment how it works but if I'm going to add it I don't know somewhere here and make sure to import everything as image picker from Expo image picker at the top like this and also make sure to call this pick image function when we press on the select image so on select image on press I want to call pick image now look what happens when I press on the select image it opens the library if I select an image I can choose it and it should uh render here no it doesn't because the image that we are rendering on the screen will always render the default Pizza image what we want is to render the image from the state that was selected and if there is no image in the state only then render the default Pizza image now we can see that the image that we choose from the gallery is actually working here so as we can see the pick image function is using the image picker lunch image image Library I thinkc it has a option for the media types so instead of all probably I will select only images allows editing this is the resizing stuff and editing that we have here if you need a specific aspect ratio and the quality here one meaning full quality 0.5 half quality and so on then uh based on the results we are setting the image in state and we see an typescript error seeing that this U string but our state thinks that it only works with null we can specify that no you work with a string or a null and in this case the error disappears here okay so our form is ready we are able to select images is displayed here we can specify the name of a pizza that data is uh tracked in state variables we can set the state it also has some uh validation for the fields so if it's only digits price is not a number one it works and with that being said we are finished with our create screen component last touch is probably you can adjust the title of it using a stack do screen and using options we can specify title create product or create dish menu and if I go here perfect I'm going to go ahead and add everything here to the git create a product going back to our taskboard we see that the next step is to prepare the user interface for the update and for the delete features here is a little bit tricky because there are two ways you can implement the update screens in a situation we have two independent and separate screens for create and update or we can have the same screen because the fields and the inputs are the same but have additional logic inside it that will allow us to differentiate if we're creating or updating an item for this use case it's going to be best if we reuse the same create screen for updating an item as well and how will we understand if we're trying to create or update well first of all let's go ahead and when we press on the edit button on the Details page we want to navigate also to the create screen so let's do that by going to the menu layout and in the edit let's also redirect to the same create screen the thing is that redirecting to this create screen we will also need to assign the ID of the item that we want to edit so because of that in the layout we don't know yet this Dynamic Property ID so instead of adjusting the option with a header right inside our layout let's go ahead and copy this stack screen which is all of this and move it to our Details page we're going to move it at the top inside the container here because remember that's also possible a viable way of adjusting the options of a screen and also in this case we don't need the name we can directly pass options make sure to import as the dependencies that it needs and if we go to The Details page we see this icon and if I import the colors correctly it should also be with a right color but in this screen we also have the ID of a product so what we can do is we will attach the ID to the end of this URL so let's go ahead and first add the string inside of the cly brackets because we will need to add access some variables then switch from normal string to a template string using back ticks and at then we are going to do question mark ID equal and we're going to add the value of our ID this question mark ID this is if you're coming from web development you're going to know exactly what it what it is but these are the search parameters that are also pared by exper router and made available inside the create screen for example these are Dynamic parameters so now if we go into the create screen even though it doesn't have a dynamic puff as the ID here because in that case we are sending a Dynamic Property we can get the ID here using the same use local search params and we can say is updating is updating will be true if ID is defined so if basically ID is defined then we know that we are updating so if I'm go going to go here I can use this is updating to change the title from create product to update product so if it's updating it's going to be update otherwise it's create product so let's see if it works if I go to the updating a product we see the title update product and if I go to the create button we see create product even though it's handled by the same create SC screen the only difference is when we are creating there is no ID in the local search parameters remember in the layout we simply navigate to/ create when we press on this plus sign and from The Details page we are appending the ID as a search parameter and it is available here and we know that if there is an ID that means that we're trying to update an item so if there is an IDE update product and we can we will update a couple of things here for example the button text should also be conditional it's either create or update and it's going to depend on is updating update otherwise create now instead of when pressing on the button instead of calling the on create we can call a intermediate function on submit that will decide what should be called the on create or the on update so let's add the on submit is going to be function that will check if is updating let's call update function otherwise let's call oncreate for the update function it's going to look similar to the on create but the logic will be different of what API calls we're going to do but still we're going to validate the input and we're going to console war here updating product reset Fields so let's call this on update when we call the on submit function and we are actually updating now if I'm going to go here to the update and press update we still have form validation for example name is required but if I do update updating product and on the plus we are calling creating product even though it's not much but we are basically defining these data flows that we will need in the next step when we will Implement uh database interactions because on the front end side it's quite similar but on the back end and it requires some additional stuff like to update and so on another thing is that whenever we're going to go to the update product what we will do is we will prefill the input forms with data of the product that we are trying to update so the name is going to be prefilled the price the image and so on but that again is going to come a bit later now we are on the update screen also add the delete button with a confirmation dialogue that's true if we are on update screen I think we should also add a delete button below the update because that's going to allow us to delete products so you're going to go to The Details page you're going to go to the update and then delete from here so let's add here another button only if is updating and we can do that conditionally with and operator and we're going to do a button here with a text delete Maybe should be a text a text button similar to how we have a select image with delete here and the style will be reused from styles. text button on press for deleting we're not going to delete right away I want to show you how we can have confirmation dialogues so let's call a function called confirm delete and let's implement this function at the top here confirm delete just like this and let's go ahead and try to go on the edit profile yes we have a delete at the bottom and when we press on it we're going to call confirm delete there will be another function on delete that will actually call the delete API call but before that I want to make sure that actually the user wants to to perform that action so console word delete in the confirm delete we're going to use a component from react Nate native called alert using alert we can uh render native alerts on the screen that can also have buttons alert do alert the first property of alert is going to be the title confirm the message are you sure you want to delete this product and if now I'm going to press on the delete that's going to be the title and the description and only one default button okay what we can do is as a third parameter we can send an array of alert of buttons let's do the first one with text cancel but will when we press will not do anything and the second button will have text delete it will have a style destructive to make it red and when we press on it let's call the on delete function now if I'm going to go to delete we see the first one cancel if I press nothing Happ happens but the second one because it's destructive is displayed with red if I press it's going to call the on delete function that at the moment just simply says delete but now we have this confirmation but dialogue which is a very common use case in a lot of cases when you have you're dealing with forms and data deleting and so on and with that we have our uh G commit we have our update and delete a product but only yeah like the UI that's what we have at the moment so we are approaching the end of the first module that was focused on the user interface with react native I hope you learned a lot during this part but in order to make sure that you're going to get the most out of this uh tutorial is to make sure that you're using different ways of learning so far you probably coded together with me from time to time maybe you stopped and tried to experiment something on yourself but I believe the best way to actually learn is to try to go a bit wild and try to implement some of the things yourself without any help you're going to go through some errors but you can always go back and look at how you did it in other project in other parts of application you can also go to Google search something as this is a very important skills for us developers you can use AI tools like ch to help you solve the issues all in all you're going to learn much better by doing it yourself by going through the mistakes yourself so I have prepared for you two assignments that you can try to do right now and then we're going to show the solution and move on to the backend side the first assignment is going to be quite uh simple here I want you to implement the authentication screens the user interface of au authentication screens is going to be this one we have two screens the signin screen with two input boxes for the email and password for the password try to make the password uh hidden like with dots look through the r documentation and learn how to do that yourself we have the buttons to sign in and the create an account button that will simply redir to the sign up screen from the sign up screen we have the same Fields the same button and a link back to the signin screen so here are a a little bit of information of how you can do that uh we will add a new group to our application and you can add an additional button that will navigate there you only have to work on the user interface in order to be ready for us in the later step to implement the authentication so yeah go ahead create these two screens you can look back at the forms that we have already build for the create product you can reuse some of these components and create the sign in and authentication screens after you are done with that I have a even bigger assignment for you and the second assignment is going to test not only some Syle like creating a couple of screens it's going to reuse all of the information that you have learned so far you're going to be able to to reuse some of the things that we created here I'm talking about the ERS page the first one is the wers list that will render a list of wers here is a very simple UI it's even simpler than our product screen so what you'll have to do here is first of all use the dummi data from our assets data orders you're going to see here some orders and R using a flat list render a list of items you're also going to have to create a custom component for the order list item in your components folder receive through the props information about a order and render it here on the screen after that there are also some solution code that you can check with because I understand this can be a little bit more challenging but at least give it a try and implement it yourself after that also there is the order Details page whenever we press on an order we're going to go to The Details page on the details page on the top you can simply render the same item as you rendered in the list and below try to render the card items from the order with their quantity their size and their price and that's it it also has some solution screens but all in all the structure of the navigation is going to be very similar to for example if I'm going to go to the user it's going to be very similar to our menu because the menu has a index with a list of things I'm going to go to the user side to do it so as we have a menu with a index with flat list you're going to have the same structure for your orders which is on this part and also a Details page with similar ways how we have a product Details page our orders are on the two right so you're going to have to move from two. TSX to a folder that will contain a stack layout to group them together so yeah I believe it's going to be a lot of learning opportunities for you to implement these assignments we have covered a lot so far go ahead and practice everything that you learned by implementing these two assignments and then come back and we're going to continue with the backend side first of all we're going to cover the solution for this assignments quickly add it in our application and then we're going to focus on the back end in the next part we're going to as I said implement the back end side and for that we're going to use super base to implement authentication database quering mutation storage real time updates and much more so there is still a lot of things to learn to become a fullstack mobile developer and I'm excited to uh to go through it and help you on the Journey of achieving that when it comes to the assignment one I hope you tried it yourself and you managed to build the sign in and sign up forms yourself if not let's go ahead and follow the solution together and I'm going to comment uh throughout doing this what's the most important parts let's go ahead and uh for the assignment one we had to create the sign in and sign up form I'm going to start by creating the group of screens for our authentication flow so for that in the app directory let's go ahead and create a new folder called off and here we're going to have three files two of them will be screens for example sign in. TSX then we're going to have a signup screen. TSX and lastly we're going to have a file for the layout _ layout. TSX for the layout it's pretty simple because all we have to do I'm going to take the code from the solution is to export a stack navigator from export router this will uh put our authentication screens in a completely different stack Navigator so we will be able to do some logic like navigating from the authentication route as a group now when it comes to the signin screen based on the UI we had to render a for with two inputs we already worked with inputs in previous lessons when creating a product so um for this form we're going to reuse most of the logic of rendering this form and working with inputs from there let's go ahead and take the solution for our signin screen I'm going to copy the code and let's bring it in our signin screen here we're going to go through the code actually let's have a look quickly at the code because it's nothing complicated what we have is at the top we are setting them stack screen with sign in then we have two text inputs with their labels one for the email and one for the password we are keeping the data in state so the value of email and set email and the same for the password and then we have a button for the sign in and a link towards the sign up let's go ahead and uh finish this uh and see the the screen in action and I'm going to bring the sign up screen as well the sign up screen as you see on the screenshots it's basically the same with only some changes to the button labels and so on so now that we have both screens how do we navigate there because if I'm going to refresh the application we land on this index file let's go ahead and add in the index file another link here that will help us go to sign in so the URL will be slash sign in even all the signin screen is in the off group because the off is in parenthesis that's an optional segment so we can directly put SL sign in here now if I'm going to press on the sign in we are redirected to this screen in order to hide the header at the top we will go into the root layout and the same way as we are hiding the header for our user and admin I'm going to duplicate one of them rename it to off and that will also hide the header on the authentication screens so let's reload the application go to sign in and here we are on the signin screen with the two Fields as you can see the password hides the characters that we are writing and that's done using the secure text entry property on the text input if we're going to press on the create an account we're going to be redirected to the create an account sign up page from where we can get go back to the sign in I pressing here or going back with signing like this so pretty simple screen but they will help us implement the logic of creating an account signing in and everything that is here on the index file is going to be handled automatically by our authorization provider so we're going to implement that in a moment and that's it that was our first assignment this one was quite easy and yeah let's go ahead and uh have a look at the next one as well the assignment 2 was a bit more complicated and the assignment 2 had the goal of helping practice everything that you have learned so far when we implemented the menu screens and the product details screens so let's go ahead and follow it together but before that I'm going to do get ad assignment off yes it worked so let's go ahead and Implement and follow together the implementation steps for the second assignment that will help us show information about the wers so as as I said the first step is to prepare the navigation screens for the user orders let's go ahead in our application so if I'm going to go to the user side let's start with the user side part here in the menu we have everything but if we go to the orders now it we have this dummy tub to screen the screen is coming from our user and here to. TSX as I said similar to how we have a menu folder with the ID for the details and the index for the list in a similar way we will have to structure our wers as well because the tab for the wers will have multiple screens let's go ahead and start by creating a folder inside our user called orders orders in the wers we're going to have three files one of them is going to be the index index. TSX and this is going to be the file that will render a list of wers we're also going to have the id. TSX that will render the word details and lastly thecore layout. TSX basically we follow the same structure as the menu here so for the layout let's take it from our menu because at the end of the day we simply have to show in the layout of the orders we're not going to need anything in the header right like buttons or icons this one is for the cart so inside orders layout let's remove this header right together with the screen options we can clean up a bit the import and for the index which will render a list of orders we'll have a title orders now we see that we have a new tab in our bottom tab navigation I'm not sure if it will work it's an empty screen but in a moment we're going to fix it I want to first of all remove two. TSX file from our project we don't need it anymore delete I'm going to close these folders inside the user layout where we have the top bar icon for the orders we have to update here from two that we just deleted to the new screen or group of screens orders and this way we have the icon back here so now we can go from the menu to the orders perfect now inside the orders index. TSX if we look at the screen above what we have to do is to render a list of order items let's go ahead and start by defining the uh screen that we're going to need for the list of ERS so I'm going to start with exporting the order screen that will return it will return a list of things for now let's simply say a text imported from react native from react native wers screen Let's uh navigate to the ERS and if we see the text here that means that we correctly render the screen now now to hide some of the headers the header that we want to hide is actually from user layout from here because we see for the menu we have a header shown fals but for the wers we don't so we're going to have to duplicate this one here not here but inside the options as well like this and we are left with only one header perfect I'm going to close a lot of these files to focus only on the index. TSX here we're going to need a list of orders so for the data in that list we're going to take it from assets data orders where I prepared a list of orders that we can work with let's go ahead and import that list in our orders index import orders from assets data orders and we're going to use a flat list to render them flat list let's go ahead instead of a text right away render the flat list data equal orders and render item it's going to be a function that will render some custom component for now let's simply do a text with item. ID if we do that we see already three IDs here which are coming from our Dum data because we have free IDs there okay for the order list item I'm not going to stop to implement it here but we will have a look at the solution that I provided somewhere here prepare the navigation create made the order list item component that will render one order and here is our component order list item a component that will receive an order and render it on the screen let's do that in our components the file is going to be called order list item. TSX and let's paste here the code inside our flat list let's import the order list item and instead of rendering a text here we're going to render the order order list item and we're going to send the order that we want to render and just like that we have a list of orders here on the left actually our order list item is using a library days. GS I'm not sure why in my case it's not complaining but we have to actually install this Library here in the guide I left a link to a documentation on how to use DJs and we are using DJs to parse the date and display it in a human readable way so all we have to do is for the installation is to run npm install dgs let's do that here and it also uses the relative time plug-in to show relative times we don't have to install anything it's automatically imported with a library so now as you can see our date where we have it here instead of Simply displaying the created ad in a format that is hard to read like this instead of that we are are parsing it using day. GS and displaying it from now which displays a relative time for example 3 days ago 21 days ago an hour ago and so on so it's a much easier way to work with days using the day GS Library other than that everything here we already know how to do how to work with that we have a simple view with two text on the left for the worlder ID and the time and on the right we have a word status everything is styled a bit of styles of on the text some Flex box and we have our custom view for displaying an order list item going back to our flat list here you can probably add some pting for the content container style and some gap between the items and just like that we have some spacing around these items and I think that's everything for the order uh list perfect let's move on and the next part of this assignment is the order Details page for the order Details page our step is to first start by creating this page and getting the ID from the search parameters the file already exists here id. TSX let's go ahead and Export here default function order details screen and it will return a text initially just for us to see so here is going to be order details we need to make sure to import uh text from react native and now if I'm going to go to the order list and press on one of these orders we should see the order Details page here we have it perfect now because we have that Dynamic puff parameter ID that is going to help us fetch the right word details we need to get that ID we do that using the use local search parameters imported from export for router and now if I'm going to display the ID on the screen we're going to see that whenever we navigate to an order it will display the right ID so this one starting with 3 2145 3 2145 what we can do here is set the title of this page by putting the text into the view uh we can also let's import the view from RE native we can also set the stack do screen we can set the title using options let's import stack from export router and the title will be a string saying word invent the ID of a word like this so now if I'm going to go here oh you see the on the admin side we don't have it yet but that's going to come in a moment let's go to the user side and if I go here the title of the page updates to show the US the order ID perfect so that was the first step and what we can do is uh based on this ID look through the product based on the data imported from dami data later on we're going to fetch it from the database but now we can manually search the order using ERS imported from assets. find we're going to find an word where. ID is equal to ID now we can add a check if we didn't find it simply return a text not found otherwise what we can do is is use this order data and render the same component that we are using for the order list item the same component that we are using here we can use on the details page as well to start rendering some information about the order so I'm going to use order list item the component from the previous assignment and we send there the order that we fetched now if I'm going to go there user orders if I'm going to click here we see cannot read proper property ID of undefined what's up with console log order do we have a typ of somewhere undefined oh because we are not returning here so if I do return not found and oh it's not going to work actually I'm going to show you why it's going to say not found because we are comparing a number with a string let's convert the. ID to string and compare it this way okay now as you can see on The Details page we also display this order list item you can add some Styles here maybe padding 10 yeah that works on the word Details page besides displaying information of the word I also want to display the items from that word this is going to be very important for the restaurant admins to know what actual uh products or dishes did the user uh order this is going to be another component that we have to build that will render an order item so that's why the component is going to be called order item list item a little bit long but let's go with it so I'm going to copy the name of it to where the item list item let's go ahead in our components and create our file for it components paste. TSX the order item list item I'm going to take it from the solution here and it will receive a word item which we can see in the types how it looks looks so if we look at the types at the order item it looks very similar to how a cart item looks it has some references to the product that it includes the order that it it's part of some information about the size and other options that the user selected and the quantity so all of this information will help us render one order item here in the list as you can see in the middle information about the pizza the size that the user selected and on the WR the quantity so uh in the order item list item let's have a look if everything is okay we have a image on the left in the middle we have some texts and on the right we have the quantity Perfecto now let's go ahead in now back in our order details screen ORD id. TSX and here we're going to render a flat list of order items if we look in our dami data we see that that each order has also order items here using a flat list from RE native the data is going to be order. order items and the way we want to render them is using a component that we just imported called order item list item and the item is item and just like that we have that uh here we can also add some gap for this component and maybe some Gap app on the root view as well to add some space around the top and the bottom list now we have a list of items that we included in that order so if we'll check other wers we're going to see that this list is different this user only order one pizza the last one ordered three pizzas another trick I'm going to show you here is the way flat lists behave when there are multiple components on the same screen the rule of f is that we only have to have a one scrollable or one flat list on a page we can have two if they are have different directions one horizontal and one vertical and another thing is that the flat list the area that is scrollable now will share the space on the screen with the word list item and what do I mean by that I mean that when scrolling the flat list the order list item will stay visible on the screen so if you see when I'm scrolling the top part stays on the screen sometimes that's what we are interested in sometimes we need something on the top that always stays on the screen other times we need that top part to scroll together with a flat list if you need to do that you can pass to the flat list components like list header component here a function that will render something it will render this order list item and if you do like that now if you scroll you're going to scroll the whole list together with a header so that's something that I thought would be important for you to know to know how to basically manage scrolling with when flatlist has some items on the top or also you can do list footer component that would also work and it's going to be displayed at the end so that is our word Details page that renders information about order details perfect before we finish this assignment we need to make sure that we duplicate this stack of screens on the admin side as well remember that we are now managing two basically applications in one on the one side we have the user screens here and on the other side we have admin screens on the admin screen we have to basically uh replicate our orders folder so let's simply copy paste it in the admin now let's refresh the page and go to the admin side we see already fre tabs in the bottom that's good let's first of all remove the two TSX that is a screen with we don't need anymore move to ban and in the layout of the admin where we target the two let's target orders here and also remember that we also want to hide the header the same way as we did for the menu if I go to the orders on the admin side we have a same view with a list of orders the thing is that you might think like why we are copy pasting uh so much maybe that's not the best way to approach it but the idea is that the UI logic that we have in these files is very minimal for example here it simply renders a flat list of items now in the next step when we will implement the backend the data that we are using will be very different on the admin side and on the user side for example on the user he will only uh see his ERS on the admin here's going to see like all the ERS in the application also like it comes down to additional features like creating updating and so on so we are just starting with the same layout and then we can adjust it based on our needs anyway for the admin I think so far we are good admins have a possibility to see a list of wers and to see the details of an Word Perfect let's go ahead and commit everything because we are done with assignment two let's have a look what other tasks we have in our UI module actually we have the last one and this is a little bonus it contains some additional uh features that we will also need for managing orders for example on the admin side we want to allow admins to change the status of uh the word so let's go ahead and render this status selector which is going to be very similar to how we implemented the size selector of a pizza on the user side when we select it so as you can see we can move through these different sizes and we're going to use very similar logic to do the status selector so here is actually the code for the status selector let's go ahead and grab it and we will need that in our admin side in the orders and Order details where we will do that we can do that in the list footer component of our flat list remember we can add a header and a footer for a flat list and let's go ahead and add the code for our selector we're going to need to import a couple of things here for example the order status list this one is imported from the types and it's basically a list an array of order statuses new cooking delivering delivered we are using that to map them and for each one of V statuses we are rendering a pressible a pressible which is a basic view that handles also press events let's import it from react native and pressable and also the colors from our constants now if we go to the admin side and check the details of in orderer we should already see the status selection and when we press on one of these statuses we are simply warning something on the screen but later uh in this course we're going to see how to actually send an update mutation to our database to update the the status of a order and also notify the user that hey the status has changed but now what it does it highlights the status that matches the word status so this one is in cooking if we look at the one that is delivered it's going to highlight the last one I'm going to commit here to have it as a separate commit the bonus feature that I was talking about is the top tab Navigator first of all let me introduce the problem that I want to solve with this and the problem is thinking about how the admins will manage the word I was thinking that if we put all the orders of a restaurant on this screen on the user side that's okay because the user doesn't have a lot of orders but on the admin side I believe that restaurants get a lot of orders every single day so it would be better if we separate the past or orders that have already been delivered from the currently active orders that need your attention like need cooking or delivering and so on so for that uh it would be nice to have have at the top a tab bar from active to archived orders when we have this kind of navigations first of all let's go ahead and see how we can Implement that so let's go ahead and open the admin side the orders and the file or the screen that displays this list is this index TSX but as we say as we said uh we want to move from having one screen that will manage the list of orders to having two separate screens one one for active orders and one for pass orders that means that if we have two screens we're going to have a nested Navigator let's go ahead and do that by creating in the orders folder a new folder called list in the list we're going to well first of all move the index that currently renders a flat list of orders so let's move index to list and let's duplicate it and for the second tab which is going to be our archive so if I copy paste it in the the index in the list and rename it to Archive we're going to have basically two screens one for index which is going to be the active orders and one for the archive we're also going to need a layout that will group them together into a tab Navigator layout. TSX so let's do export default order list Navigator we need of a function and what it will return let's start by returning that tabs navigator from Expo router now if I go to the wers there is a problem because now in the wers we do not have a index so going to the admin orders the list index it's a bit weird what's happening here in a way it's working when we go to the wardex we have another tab navigator on top that maps from index to Archive index to Archive but as we said we wanted these tabs not to be on the bottom but to be on the top the thing is that at the moment when recording this tutorial Expo router did not support that material top tab navigation out of a box it only supports tabs stack and drawer that's not a problem because we can integrate expor aor with any other Navigators especially the ones that are coming from a re navigation library because as I said before Expo router is built on top of react navigation let's search here material top tabs Navigator we see that this is exactly what we need some tabs on the top and in rack navigation that is accomplished with material top tabs Navigator let's go ahead and start by installing this uh type of Navigator by installing the first set of dependencies in our application and going back to take the second installation for the re native pager view let's wait until it installs now that we we have that we can have a look at how to create a navigator with a top tab Navigator so we see that we have first of all to import this create material top tab Navigator we're going to do that in our list layout where we want to create the tab Navigator and now using this and the with layout context imported from react native we can create a custom Navigator and connect it to the Expo router we do that by by declaring the top tabs is equal to layout context and here we are creating the material top Tab and we specifically access the navigator from there just like that we created these top tabs that can be exported from the layout were used with all the configuration and all everything else available inside the material top tab Navigator we see that the tabs now are displayed at the top the index and the archive based on their names of the files that's pretty cool and uh let's finish with some adjustments here first of all uh we need to hide the list header the list header is coming from orders layout we can access here probably the list and instead of the title we can say header shown fals now if I'm going to go to wers yes the header is removed but now the tab bars are displayed below the safe area view below the notch on iOS we can uh fix that issue using a safe area view let's go in our list layout where we have our top tabs we're going to import the safe area view from react native safe area context and we're going to Simply wrap it around our top tubs and when we wrap components into a safe area view on the top it protects us from the notch on the bottom it protects us from this also bottom thing if we go to the wers what's going to happen uh well nothing is going to happen because we need to also provide some style here the style that we need is flex one to make sure that the this container takes the whole Space we can also say background color white to make the safe area white and we see that at the top it correctly change the color if I don't have it as you will see it will display with gray below the safe area but if I have a background color it displays properly but on the bottom it also displays some area here and this area actually is the same amount of size as the bottom notch on the iOS so if we only want the safe area view to work on a specific Edge in this case we only work want it to work on the top Edge we can specify that using edges and if we say only on the the top it will apply ping only on the top and we get rid of the unnecessary ping on the bottom now we can move really nice between index and archive and I think there is also one more issue if I go to the admin orders we see that layout no route named index exist in the orders should we simply remove the index from the layout and will it work now if I go to admin orders yes it works we can go here we can go back from archive as well we can go back if we go to menu and back here it remembers where we are there so perfect it works pretty well the only thing that is left is maybe to change the names of the tubs and it's the same approach as we are uh familiar with for changing the names of a stack or other screens so for the custom top tubs we're going to add here top tabs do screen with a name index we can change the options of it to say title active perfect so that's how you can uh Implement custom Navigators using exper router and in this situation we did that using material top tab Navigator and this brings us to the end of the first module related to the user interface the next part is going to be the back end welcome to the module two of our full Stack mobile app development masterclass during this module we're going to implement the backend side of our application of our food watering application and we're going to do that with superbase super base is an open-source alternative to Firebase but I believe it's much more than that it started as an alternative to Firebase but now it's a very powerful backend system for mobile and web applications so in this module we're going to get started with superbase we're going to create a project and and learn more about the platform that we will work with then we're going to implement the authentication system we're going to do the creating an account with email signing in and managing the session and also on the front end side we're going to implement the proper navigation and protected routes then we're going to design our database and we're going to start the quering and mutating the data we're going to implement the crude operation which stands for create read update and delete for our models for our products ERS order items and we're going to learn uh and use react query as the quering and fetching library that will help us cach and get data from our API then we're going to implement the uploading images and storing them in on superbase storage in the cloud and lastly we're going to implement realtime updates we're going to subscribe to updates to for example new orders and as soon as a new order is created in the database the admins will be notified and they will see it appear in the list the same thing on the user side if a order changes the status they will automatically receive this updates so a lot of exciting things today make sure to follow the project guide because uh we have all the steps that we need there and we also have there additional details that will help you move along okay if you are ready we can get started with module 2 and implementing our backend site so the first step for our backend is to configure create a new super based project and configure it in our R native application and make it ready for the next features like authentication datase and so on you can open up the documentation of super base from here the getting started guide but we're going to do it step by step together so let's go ahead and first sign in into super base account you can do that using your GitHub account that's what I did so on our dashboard let's go ahead and create a new project I'm going to select my organization and for for the project name I'm going to do food word ring the database password um add the strong database password here but make sure to remember it then we can choose the region where our servers will uh be located uh you can choose one that is closer to you or that is closer to your end users let's go ahead and press create new project and we're going to wait for super base to set up our project initially when setting up a project superbase will uh configure our postgress SQL database postgress is a relational SQL database which is quite powerful and very well documented there are a lot of resources out there that will help us navigate and create tables and query them while we're waiting for uh the project to initialize we can actually continue with uh with our guide configuring super base in our project what we need to do and uh you can check in the get started guide is we have to install some dependencies I'm going to actually copy them from our guide to install super based GS and some extra dependencies let's go ahead and install them here the next step is actually to create a client and configure it and make it ready for us to use it so here is the configuration file that we're going to copy from here and create it in our source in a new folder lib that will uh hold the code for our libraries and here we're going to have um new file called superbase dots let's paste the configuration here and the only thing that we have to change is the superbase URL and the uh superbase key to get them we're going to go back to our project and we see that it's it finished uh setting up so we can go to the project settings from the settings let's go to the API and here we have a URL copy the URL we need that in our superbase URL and the second part is this unknown public key this is a safe to share uh key because later on the way we will Implement authorization on our API is going to be based on whether the user is authenticated or not so it's going to it's safe to to have it in your code now super base is ready actually to start interacting and working with our back end here the configuration step is done let's go to the next task and in the taskboard that's going to be authentication during this lesson we're going to implement the authentication steps for our application we're going to start by creating an account on on the sign up screen signing in on the signin screen then fetching the session information and using a react context provider share it with all the other screens in our application to be able to properly navigate the user and protect the routes based on the information about his profile like the group he belongs to is it an admin on a user and in general like if he's signed in or not for that what we have to do is uh we're going to start with the sign up flow let's go ahead and start with the sign up screen because the first step is to create an account how do we do that well let's open admin off sign up and that's where we will have our code first of all we need a function sign up with email or let's create it with a sync function and here we can start by doing a console war sign up let's link this function with a button click so so when we click on the create account we're going to call sign up with email press create an account it doesn't work so that's a very good thing to always check because yeah I have a typo here it should be on press if I press sign up perfect so what do we have to do we will do uh we will first of all import the super based client that we have defined in our library so we can do library super base now using this client we can call the off module I think I need to destructure it yeah now it works so uh superbase do off and here we can call the function sign up and provide the options the options required is the email the email we will take it from state so we can leave it the same because it's the same name and the password so because it's the same name we will simply have sign up email and password we can go ahead and get the results that super basee will return and one of them in this object is going to be the error if something happens for example if error let's go ahead and simply using an alert from react native show the error. message now if I'm going to go to create an account if I do some specific mistakes and I'm going to press create an account we see the super base returning as the error password should be at least six characters perfect we can then actually do some proper data and if I'm going to press create an account nothing happens but behind the scenes I'm pretty sure our user has been created if we go in our dashboard we can look at our authentication Tab and here we're going to see the newly created user we see also that it's waiting for verification so if I look at my email I already receive a verification email that I can uh confirm my uh email account you can leave it uh like that if you want extra protection but what I'm going to do is I'm actually going to uh turn off this requirement of having to validate the emails and we can do that in the authentication providers uh I'm going to select the email provider and here I'm going to uh disable the confirm email and just like that I'm going to press save let's go back and create a new account here for example I don't know create account and if I go back to the dashboard the newly created account should be there perfect additionally I want to show you how you can also track the loading state in order to prevent this function to be called multiple times so we're going to have a loading State set loading use State and yeah it's false when we call this function sign up with email we will set loading to true and when we finish the execution of this function we're going to set loading back to false and with this information we can go ahead and disable the button disabled if is loading so if is loading the button is going to prevent us from creating another account like when we wait for it and you can also like with this loading you can have like additional UI uh feedback for example I can change name if it's loading from create an account to creating account and then dot dot dot and now if I'm going to from the sign up if I'm going to do create an account we see a label after that it finishes it disappears and it will also prevent us from creating pressing it multiple times while we wait for the response that's a very common use case to stop the multiple execution of the same request so with the sign up we are finished let's go ahead and do the same for our sign in actually I'm going to uh look at the sign up and copy this sign up with email including the loading state so let's copy this function and bring it to the sign in here we're also going to in the signin screen to import the super based Library let's rename from sign up with email to sign in with email and here the function that we will call to authorization is going to be sign in we need to actually specify sign in with password then we provide the email we provide the password we need to import alert because it's used if there is any errors and let's hook the sign in with email to the button so on press is going to call sign in with email the button will be disabled if we are loading and the text can also be if is loading like this just for us to see something some user some UI feedback so now if we go to the signin screen and use any random email we should probably see an error invalid login credentials perfect if I'm going to use a proper email here that I created an account with we should see signing in no error which means that we correctly sign in and the user already have a session but we're not done yet because the next steps is going to be to fetch this session that the user gets from superbas with all the tokens and so on and use it to properly navigate the user to the right screen but with signing in and sign up we are finished and as you can see it's pretty straightforward to do that we simply created the project with super base and automatically we get authentication out of the box without having to set up and configure anything else then with superbase do off we were able to call them sign up and sign in with password and everything works out of a box our users are managed in super base we can see a list of them here in the dashboard now moving on to the next step the next step is going to be about authentication provider as I said our user correctly creates and signs in when that happens super base gives him a session a session with some tokens that will authenticate and authoriz him to make the next request to our database and so on we need that session in a lot of places in our application so for that reason we're going to create an authentication provider that will take care of this session and yeah let's let's get started by creating one in our providers I'm going to start with naming it of provider. TSX remember from the card provider the steps that we have to take in order to create a react context provider first of all we need the of context that we can create using Create context imported from react we're also going to need a type for the of data and this is going to be used as the type of this context we need to provide the initial value of empty object now the provider let's export default function called off provider this function will receive some children which is a re node so we can type it using props with children and what it will do it will return the authentication context. provider with its value that we're going to Define in a moment and inside it it will render the children now what's left for us to do is to wrap our application in this off context provider and then come back and provide the data that we need here but first of all let's go to application layout because here is where we also have a card provider let's import the off provider and let's use it in our root layout navigation to wrap our stack like the root stack and I'm even going to wrap our card provider because the off provider is something it's basically the first thing that we need there all right so authentication provider is there uh now what do we need to do in this authentication provider let's go ahead and query the session of a user we're going to do that when the off provider is initialized or is Mount Ed so for that we need a use effect with an empty dependency array and that means that this is going to be executed console log of provider is mounted when the authentication provider is mounted so if I'm going to look at our logs restart here quickly we see the log of provider is mounted at this moment what we can do is we can fetch the user session from super base so because Val is going to be a in a sync function let's declare this fetch session a sync function because we cannot run a sync code directly in a use effect we need a function and then we need to call this function right after declaring it it's a little trick that I don't like very much about react but we have to do that now inside this uh fetch function which is a sync we can call asynchronous functions for example a weight super base uh let's import it from our lib super base do off. get session let's have a look at the result result of the get session if I'm going to look there and restart the application we don't see anything because we haven't console logged the result so we see some data we see some errors so it follows a very consistent way of giving you data it gives you an object with data error and probably also loading is loading but if we can look at the data and inside the data so let's console log data and see what do we have there we have an object called session so that's what we are interested in data do session let's go ahead and Define a state variable where we will store the information about the session is equal use State uh initially probably it's null but the type of it is going to be session imported from super base Library session or null now we can simply do set session with data do session let's go ahead and Export this session using the uh off context provider because based on it we're going to identify if the user is signed in or not I'm going to start by defining the session in our type so the session is of type set session or null let's initialize it with null here when we create the context and make sure to use the session from our state to export it through the of context provider value now here we are setting it in state and I think that's everything that we need here now if I'm going to go ahead where for example on the index. TSX here where we are rendering everything let's go ahead and try to take the session so session equal use off oh we haven't provided the we haven't defined the hook use off that gives us access to the context uh we're going to do that now let's export it as default from the provider export const not as default but as a const use off that's going to be a custom hook that will help us get access to our context now back to our application index let's import useof from our providers and let's see what what do we have here in session if we have access to the session if I'm going to refresh we see that on this screen we have access to the session and based on the session we can redirect the user to the right place for example we can check if there is no session let's return a simple redirect component that will redirect us where well if there is no session that means the user is not signed in so we can redirect him to the sign in screen and our wise the user will see this screen so if I'm going to refresh we are back to the signin screen why because we thought that we are logged in we saw the session in our console log why we're still on the signin screen well that's because initially the session is null but we should wait for the session to be fetched and only then take a decision whether is over indicated or not so let's go ahead and add here a loading state in our off provider loading set loading equal use State and initially it's going to be true because when we Mount we want to initialize with true to say that hey we are still loading we are not sure if the user is authenticated or not and only when we finish fetching the session information we're going to set loading to false now let's go ahead and Export this information from our context so loading is going to be a Boolean initially it's going to be true and we export it with a value here loading now in the index. TSX when we take this decision let's go ahead and first uh check if it's loading if it's loading I want to Simply return an activity indicator a spinner so now if I'm going to refresh we see that we're not redirected there initially there is a loading State and only after that we are back to to this part to this buttons because we are already signed in if you're interested how we can do the sign out we can add a new button here below with sign out and on press we can call Simply superbase do off do sign out if we do that and press on the sign out button nothing happens but if I refresh the page we should be redirected to the signin page perfect that's what we want and that's happening because when we reload our off provider is loading the session and it fails to load the session because the user is not signed in and we get here and we get automatically redirected to the signin screen from here we can go back and signed in and we're going to receive a response but again nothing happens automatically we will have to restart the application to go to our other screens why is this updates not happening automatically well because the session is only fetched at the moment when we Mount the component which basically stands for the initial session the initial session when the application opens as the user uses the application this session can change things can happen like either a user can uh sign out or he can sign in or he can create an account so what we want to do is to register and listen for session updates and when that happens update the session in the state this way we will have this real time update of a session and navigation from authenticated to non-authenticated to do that we have we can subscribe using this super base off off State change and we're going to do that inside the same use effect which means that we're going to subscribe when we launch the application when the off provider mounts and we sign for the off State change and whenever that happens we we are updating the same session in our state and now probably I'm going to refresh first if I'm going to press on the sign out we should automatically be redirected to the signin because superbase will trigger this function it will update the session with a undefined or null and back on our index. TSX the session is going to be null and it will redirect here so everything happens automatically at the moment where we are managing the red Direction is on this index. TSX the first screen that will be loaded when opening the application with exper router we can also run our application on the web and the problem with uh that is on the web the user can manually change the url and get to a place where he doesn't have access to for example if he is not authenticated he will be redirected to the signin but he can manually go ahead head and type SL user SL men and he will be he will get there because nothing stops him from doing that well for that we have to protect our groups with some guards with some rules let's go ahead and first protect the authentication screens it feels a bit weird to protect the authentication screens but we don't want already signed in users to somehow get here and that's what happens right now we signed in but we still remain here so what we can do is let's go ahead and import the session here from use off and we're going to do the guard here so if session is true that means that the user is signed in then simply return a redirect we can redirect to the home screen and the home screen will take it from where and redirect where the user has to go but what we want here is basically redirect away from this group like you don't belong here if there is a session if there is not a session simply render the the stack screen and this should have fixed the problem of automatically redirecting to the index when we sign in so let's sign out type our login details again sign in and we are automatically redirected here even if I'm going to try to go back it doesn't allow us to good so now we have protected the off layout all the screens inside SL off are protected and only unauthenticated users will be able to see them let's do the same for the user side layout in the tuab layout we are also going to get the session and we can do the same if session here is not defined that means that the user is not authenticated simply return redirect we can redirect to the slash we can always redirect away to the Slash and then the slash will take care of the rest of the navigations so now our user side is protected by a guard as well for the admin we need some extra features and we're going to get there in a moment so far we have um implemented basic authentication flows meaning that when the user is not authenticated we redirect him to the sign in and signup screen when he is authenticated we redirect him to the user screens but we also have the admin side part and for the admin side we have completely different rules and how we're going to manage that we're going to see in the next steps for that we need to first of all be able to set some additional parameters on the user profile and be able to set the group that he belongs to because this is going to be group based authentication or authorization so what we actually need is going to take a couple of steps but we we need that in order to be able to manage additional fields on the user profile at the moment if we go to the tables we see that we don't have any tables available in our database that's because the schema that is selected is the public here in the public is where we will store all the tables that we Define but if we select from here we see that there are other schemas for example the off schema is where all the authentication information is store including like users and so one right what we want to do is whenever we need to store additional information on the user we need that uh to keep track of his information in web public schema so what we are going to do is we're are going to create a profiles table in our public schema we're going to link that with the authentication table that is managed by super base and we are going to create a postgress SQL function that automatically creates a user profile whenever a user is created in the authentication users table it might sound complicated but it's way easier than expected because there is a predefined template for that so what we can do is we can go to the SQL editor and here there are some quick starts and user management starter that's what we are interested in so if I'm going to press on it we're going to see like a predefined SQL file that will be executed to create our profiles table with information about the user like ID username and so on it will also create a function that will handle new user creation so whenever a new user is created the Prof a profile will also be created and automatically linked to the user from the authentication table and that's most of it it will also set a storage but we don't need that at the moment so don't change anything here simply press run to execute the query and create that table we see that the result is Success we can go back to our tables and we see here profiles at the moment there will be no profiles because this table just has just been created but let's go ahead and create a new profile so let's give it an email creating an account we are redirected to the this home screen and right away we see the profile line appears here if we see this ID ending with 6 C8 matches the ID of the user that was just created so if I look at the authentication Does it show the IDS as well well yeah it shows it here in the user ID so if I copy yes it ends with 6 C8 so that means that now our table profiles is linking to the user that is generated but now we can manage data here we can query data here and we can add additional fields and information that we want to store about one specific user also you can have a look at the database schema visualizer and you see that this newly created table is linked to the of user ID that's important in the next steps but for now what we want to do is to edit the profile to add a new column for every single user that will specify the group he belongs to so let's edit the table and Under The Columns we can add one more column called group this group is going to be of type text and the default value let's call it user I'm going to open the settings here and say that this is an this is a required field so I'm going to deselect the is nullable now let's click save and this way our users now will have a group column if we scroll through these columns we see group user what we have to do next is to fetch the information about the profile and then using this group we will be able to redirect to the admin side or to the user side so let's go ahead and where we will query the information about the profile well you guessed it right we're going to do that in the off provider here we're going to besides keeping track of a session we're also going to keep track of a profile set profile use State this is going to be of type profile that we can define a bit later so how do we query the profile well I'm going to check our documentation group based navigation so here is our code that will fetch the profile from the super base let's take it from here and in our off provider where we fetch the session after we fetch this session let's go ahead and do actually shouldn't be if session but if data do session if we received this a new session back from super base then we also want to query the profile so let's query super base from profile tables we're going to select everything about the profile but we're going to only look for the profile the ID that matches the session so it should be data. session. user. ID but data is also here so you know what I'm going to go back to session and simply destructure the session from the data right away here and we can remove it like this and set loading false is only going to happen only after V statement so only after trying to get the profile as well we want to show loading indicator until we know enough information about the user to decide where he should be redirected Now set profile data let's have a look at what this profile is so console log let's do profile if I'm going to look here we see Avatar null full name null and so on but the group is user so that's very very important for us group is user what we can do is we're going to export probably the profile here profile at this point let's put it any I'm going to return back and add a proper profile null and let's export it in the value as profile should I add here a simple variable is admin which is a Boolean and it's going to Simply ify how we query it because we can look at the profile but if we export simply aoan is admin is admin we will initialize it with false and here in the value we're going to export is admin profile question mark. group only when the group of a profile is equal to admin will he be uh an actual admin now we can use this easy admin well first of all in the index that handles this right directions so after this check let's go ahead and also take the is admin because if he is not an admin well if he's not signed in he's going to be redirected to the sign in if we get here it means that he is signed in which means that if he is not an admin let's simply redirect him to the user side uh to the user side but if he is admin I'm actually going to let him uh see user admin and so on except the sign in I don't think he needs the sign in so an admin will have a possibility to choose does he want to look at the application as an admin or as an user so now I'm going to refresh we are redirected to the menu here which means that we are a user right that's the logic and we cannot go back we cannot go to the SL off we cannot go to the slash admin and so on actually to the slash admin we will be able to go if we manually navigate to that screen I can show you that on on the web where with deep link but trust me we will be able to do that because at this moment we haven't added a guard to our admin layout so what we can do here is we will get the is admin from the use off and we're going to check if he's not admin he doesn't belong here so let's return a redirect to HRA slash because without V let me actually show you something without easy admin here let me show you like a simple mistake that you can make for example in the user I'm going to go in the menu layout and here in the header right I'm going to Simply say when we press on the card don't go to the card but go to the admin so even though we are a user we found an admin guard here we will be able to get here somehow either by a mistake or a bug or by manually changing the URL or by sending a a deep link but if we for example have this even if there will be a bug like that where we are going to try to change the menu we're always going to get back to our place because this layout is protected perfect okay so let's not forget to change back here to card yes that's good and we saw how the user is redirected to the user side let's go ahead and change in our database manually the group of our user to admin if we save changes and go back to our application and refresh we're going to see that we are redirected here because an admin can choose he wants to manage or he wants to check the user side application so he has access to both of them now all our routes including the admin layout is protected the off layout is also protected and the user layouts are also protected with the session redirect and in the index we decide where he should be redirected perfect so with that being said we are finished with our authentication so yeah I hope you you learn something new here I know it's a lot of things like uh all over the place like a context a lot of screens a lot of CS uh some changes to the super base but at the end of the day like it's a lot of pieces but they are quite understandable I would say all right so we are finished with authentication and let's go to our next step the next step in our plan is the product crude operation the create read updates of the products this is a quite a long lesson we have to implement a lot of these operations we're going to start with designing the table imp implementing it and then fetching information in our application for fetching we're going to use the re query library and we're going to implement like the details read product by ID the creating a product updating it and finally deleting it so without further Ado let's jump into it and start by creating the product table the product table we will create it based on the data that we already have in damid data or B based on the types so if we look at the type a product has an ID it has image name and price let's go ahead and create a table where we will store our products or dishes let's say so from our uh super base project let's go to the database actually and under the tables let's go ahead and create a new table for the table name I'm going to name it product with lower case P you can provide here some information uh leave a in enable roow level security by default we will talk about that in a moment and Under The Columns let's add some extra columns for the name uh we said that we have image and we also have price now let's go ahead and select the data type and name will be a text so let's select text from here image can also be a text and price will be a float number it can be float four four means how many uh SES are used for uh the data so how large these numbers can get if we look in our guide you can double check the data and the types that we have here and we see that we also have to make sure that the name required so let's dis select is nullable and the same for the price the image we will leave it as nullable because some products might not have the image with that being said let's go ahead and press save and just like that we have a a new table ready for us to to store data ve and to query it if we go back to table editor we can look at the products and we can go ahead and insert manually some rows for us to be able to query the IDE and created that will automatically be created for the name let's do I don't know Margarita and price $9.99 and the image I'm going to leave it empty because that's possible we can add one more for example name pepperoni and let's press save now as you can see the IDS are automatically managed and auto incremented there is also an automatic field created that that is managed automatically by super base which is great and the name price is here so the next step is to try to fetch this data query this data in our application let's go ahead in our rec native application and where we will query the the product is on the menu and let's start with the user side so up user menu and here index for the list of products here we can go ahead and fetch uh the information about products when do we want to do that we will do that in a use effect when the component mounts we want to fetch the products so when component mounts we need to do something that means that we need a use effect with an empty dependency array now here what we can do I will create this fetch product a sync function because remember we cannot run a sync right directly in the use effect we need to declare a function and then call it like this and here what we can do is we can use the super base to query our data so superbase dot from and here we need to specify the table name so let's say that the table name is products what we want to do is we want to select and here we specify the columns if if you want to select all the columns we're going to use the star and what we will get back is uh data and error let's go ahead and check this information by console log and I'm going to start by console logging the error because I'm pretty sure there is an error so if I refresh and go to the user actually there is no error that's a bit weird let's see the data then the data is empty and that tells me something that the data is empty even though we have items in our database why is that happening well that is happening because of the permissions remember if when we created we selected this enable Ro level security this is how authorization uh works and superbase is leveraging the roow level security authorization from postgress SQL pogress SQL has this authorization rules that we can create to add some logic to our queries to make sure that only specific users are allowed to do specific actions these policies are defined on the table and we can create multiple policies for different actions targeting different users and groups of users by default nobody is allowed to do anything like nobody can uh can query the data unless he is a root user like unless you are the admin of a project to enable someone to do some oper ations we're going to go to the table in the table editor and we can view the policy here so let's press view policy and we see that it doesn't have any policies yet let's go ahead and create a new policy there are some get like quick policy for example to enable read access to everyone but I don't recommend that because we want only authenticated users to be able to read products the rules that you enable here will depend on the user experience that you want to provide for for example if you want anyone to be able to view a list of products you would add this read access to everyone for example if checking your menu can be done by anyone you would be interested in that and then only checking creating wers work checking the wers can be specific to authenticated users what I'm going to do is I'm going to protect all my routes only to allow authenticated users to do uh requests there so so uh actually I'm going to go back and uh choose the full customization here for the policy the policy name will be allow authenticated users to uh select we're going to select the operation that we want to allow for now to keep things simple let's do wall we will allow All Rolls authenticated here is where we specify to which type of users this rule applies a non this this is anonymous authenticated this is authenticated users and using expression I'm not going to have any specific logic here like if you are authenticated I'm going to allow you to do that maybe we can talk about more specific policies more granular policy a bit later but for now let's keep it simple for us and allow all operations on our products table for only authenticated users so let's save a policy and now if I'm going to go back to our application and restart a and go to the user side we're going to see right away some data here so that's perfect what we can do with that data is store it into a state variable maybe also add the loading indicator or loading State uh maybe we will also need a uh error state so as you can see where I'm leading with this is that while it's possible to fetch data from super base directly in our component doing it yourself with without any extra Library it's going to get out of hand pretty uh easily because in all the projects we're going to have an effect we're going to have a couple of State variables for data error and so on so it's a lot of work for that reason what we're going to do is we're going to use the react query Library react query is a very powerful State Management and also data fetching uh library that we will use to fetch data and and we will Leverage The Power of the caching mechanism to keep the data in sync on different screens for example when creating a new product we can refresh the product list and so on you're going to see the power of it in a moment what we have to do here is we have to start by installing react query so let's go ahead and copy that command here npmi t/ react query then we will need a query provider where where we will create the query client and provide it to the rest of the screens so let's copy actually this code here because there is nothing interesting there and let's go ahead and in our providers create the query provider. TSX what we do here is simply create this client and using the query client Provider from the library we are exposing this client we still have to import it in our root layout up layout let's import it here query provider with a name query provider I'm going to put it below the off provider because the query provider will need to know information about the authentication but I'm going to put it above the cart because inside the cart we will need to run query so the cart depends on the query provider that's why I decided to put it in between now all our screens will be able to to run uh queries and mutations for our data using react query let's see let's go to our back to our menu index where we are fetching this uh orders using super base and let's see how we can uh transform this one to a query what we need to do is we need to import the use Query Hook from T rect query and at the top of our uh component we are going to use it use query now use Query needs uh some options so let's define the object with options the two important properties is the query function which is the async function that will be executed to get the data but above that we need the query key and the query key is uh helping react query cache the query so we're going to uh the query key should be an array and here we will specify what this is our our products we're going to see in a moment like different ways to Define these query keys and how they can help us now in the query function we need to specify how do we want to fetch the the data react query is very flexible in terms of how you're going to bring the data so you have to write the logic here we already wrote the logic of querying our data so let's copy it from below and put it in our query function now what we need to do is if our super base returned the error let's simply throw a new error using this error message we have to throw it in order for react query to understand that hey there was an error because later on we're going to be able to get it right away from here but if there is no error what we're are going to do from here is simply return data and this data is what we return from the query function is going to be uh accessible through data here at the top and besides this we also have for example the is loading which handles the loading State now what we can do is I'm going to remove the use effect here is we can check if is loading let's return an activity indicator to show that hey we are loading data if there was an error so if error then uh return failed to fetch products make sure to import text from react native and let's go to the user side here we saw the loading indicator we didn't see any errors but I don't think that this data is coming from the database the flat list is still using products if we change from products to data right away we see the data and information coming from our database you can now use with work with data where you can rename the data here to product and it's better to rename it to keep the naming like clear like hey this is an array of product and if I'm going to go here yes this this is the data from our database and we can safely remove a use effect and the product the dummy data with products we no longer need them so uh it's quite a lot of things to to unpack here probably but the benefit of react quy here is that it manages automatically for us the loading States the data the error States it also manages and optimizes our query behind the scenes knowing this uh query key and if from other screens we're going to send the same query with the same Key Products it will know not to double refetch it or to take it from the cache and another screen where we will need to run the same query is going to be our admin side instead of copy pasting the whole logic of how to query our products it's going to be better if we create reusable functions that we can use across our application whenever we need to query products for that what we're going to do is in our source let's create a new folder API and here to keep all the helper functions that will help us fetch data or M mutate data let's start with creating the folder for our product and let's start with the index.ts we're going to use custom uh hooks so let's start by exporting a const a custom Hook is a simple function it's recommended to start the name of a function with use in order to basically tell that hey this is a hook and the name is going to be use product list what this will do it will do everything that use Query is doing so I'm going to copy everything from here and move it in our use product list let's import the use Query here and we also need to import super base and instead of D structuring the result I'm going to Simply return the result and if you return the result whenever we will use this used product list we can basically replace all of this Ed query in our menu index and the structure it by simply calling use product list that we can import from our API products and we don't need the use Query and use super base anymore so with this approach we keep all the logic of querying data in our API folder and then our components they are pretty lean which means that not doing a lot of heavy work on fetching or thinking about like how to fetch how to group and so on it simply uses our custom hook use product list and it will give back like the data error and is loading another things that we use Query bror then based on that we simply re render different things on the screen so now if I'm going to go to the user we see the menu if I'm going to add a new thing on our in our table name new new price one 12 three if I'm going to save come back here reload go to the user side we see the new uh Pizza the new product appear in the list to replicate this Logic on the admin side is going to be easy like let's go ahead and from the menu screen copy these lines using the used product list the is loading that shows the activity and the error let's copy it from here go to the admin menu index and inside the menu screen of the admin site let's go ahead and fetch our products uh let's import activity indicator import text and remove the dummy products from here just with this couple of lines if I'm going to go to admin side we see a loading indicator and we right away see the pizzas here perfect so that's how we fetch a list of data from the API our next step is is to implement the next operation read product by ID starting from here we are going to follow pretty much the same approach whenever we need to implement a functionality we will go to our API we will create this functionality as a custom hook and then import it where it needs to be used like on the screens that it needs to be used so let's start with creating a new hook for reading a product by ID so use product this hook will also need a an ID because we need to know for which actual product we want to query now I'm going to copy the same query below and we're going to adjust it a bit I'm going to start with the query key this is important because if we're going to do the same query here it will basically overwrite our products so what we should do is probably change this key to specify that hey this is a completely different query the rule of f is to use the variables that differentiate the queries in this case the ID as one of the values here so if I'm going to paste the ID here query to the products with ID one will be cached separately then a query to the products with id2 and so on so that's why we need the ID there to store them in different places in our cachee now to our super base thing is we're going to use from products we're going to select everything and after selecting we will also add the equal operator where we can specify the column that we want to filter based on for example ID we want the ID to be equal to the variable that we receive this will return an array of things but we're interesting in only one item so at the then we can simply put dot single and it will take the first item and return it as an object not as an array we can leave the same here if error from error otherwise return data now that we Define the the query we can use this hook in our application user menu ID basically from the user side whenever we press on one of these pizza we want on this page to query that data about that pizza uh let's go ahead and probably after getting the ID here we're going to use product from API and let's take here the as always data which we can right away rename to product the error and the is loading the used product here expects the ID we need to fetch a product by ID we could use this ID but the problem is that this ID is of type string or actually an array of strings so what I'm going to do is let's rename this ID to ID string and parse it to a number ID using the parse float ID parse float ID helps us transform from a string to an ID but now the problem is that this ID can also be an array of strings so with some magic here by checking the type of ID string if the type of ID string is string we're going to return ID string otherwise we're going to return the ID this string at position zero so if it's a just a string return it if it's an array return the first item from there and now the ID is of number and we can use it here so this is a little bit ugly but it is what it is now make sure to also uh remove a line that manually Loops through the dummy products so remove this line because now the product is being fetched and we can remove a import as well now if I'm going to go to the user side and press on the margarita we see $9.99 at the top Margarita if I go to pepperoni we see the updated price which means that it's correctly fetched from the server but you should also make sure to add the checking if it's an error or if it's loading so the same way as we had like for example on the index with this isas error if is loading or if is error we can have it as well before our main return statement and I don't need this if product is under find okay now if I go there first should show a loing indicator and then the pizza perfect and if I go again you see that's another thing like if I'm going to navigate to a new product you see a loading indicator for a couple of milliseconds but if I'm going to go to a one that is already loaded in cach it automatically like without even showing the activity indicator and that's the power of react query cache whenever we do this remember to also do the same logic for admin side so on the admin menu detail screen we have to do the same steps so from this part let's first parse properly or let's take these three lines of parsing ID and querying the product I'm going to move them to our product details on the admin side let's import the used product from our API and let's make sure to remove this line that finds the product from damid data and we don't need it anymore here now test it by going to the admin side and pressing on one of these items you there was a line saying that it's not found just because we didn't we don't have this if loading or if error in the admin side so if you add them and import the activity indicator it's going to show properly the loading State and only then display the details okay perfect all right so let's continue with our cud operation for our products so far we have implemented the read operations to read a list of products and the details of one product knowing its ID the next step is specifically for the admin side because admins should also be able to create products whenever they uh fill in and complete this form so uh let's see how we can do that uh and we're going to start by implementing in the API product index a new hook for uh creating a product so let's export const use insert product and this is going to be a hook that will uh return as you can see above we are returning a used query in the previous queries the thing is that before like here above uh we are querying we are getting data from a server in the inserting a product this is a operation this is mutating something on the server so for that we need another Hook from uh react query called use mutation so let's return here the use motation and the options that the mutation expects is first of all the mutation doesn't have a query key because we are not querying data we are sending data so it only has a an a sync function called mutation function that will receive some data we can type it with any because we are going to cover the types in the next lesson and here inside the mutation we will receive the data and we need to do something with that data what we're going to do is we're going to use super base to uh insert some data in that database so as well with a weight super base we are also going to use from to Target the table that we want to work with and the table is called products what we want to do is we want to insert a new line here we need to specify the data that we want to insert in the product column when we try to insert manually ver row we know that the ID is automatically generated together we've created that but we need to specify the name price and image let's do that here so insert name is going to equal data. name image is going to be data. image and price is going to be data. price now it will also return back error if that happens or that data or data but the data we will get it only when we call single at the bottom let's see now let's have a same checks if error throw a new error if data simply return data the data is already here let's rename the data that we received as new product and we're going to return the new product now let's go ahead ahead and use this mutation inside our create screen that screen is in our application admin menu create and at the top after all of these fields let's go ahead and use the newly created hook use insert product the information that use insert product returns is everything that the Ed mutation gives us back and the Ed mutation will give us back a function called mutate whenever we call this function we are executing the mutation function that we defined here so it doesn't execute right away it's a function that we can call to uh create or to to execute it let's rename it to insert product Now using this insert product what we can do is go to where we have the onsubmit on create uh yeah here we have the save in the database so what I'm going to do is I'm going to Simply simply say insert product and the variables should be well the name the price and the image the problem with the price is that in our state the price is of type string in the database we need to save it as a number so what I'm going to do is I'm going to uh for the price I'm going to parse float the price from the state and this way the price becomes a number let's give it a try and see if we made any mistakes I'm going to go to the ad inside create let's do I don't know from the up 1 2 3 4 Create creating from the app yeah because it's here uh let's have a look in the database from the application yes it has been created successfully if you have any issues with creating it so far double check the policies and make sure that the product table has a policy that allows uh insert operation for authenticated users again gave authenticated users permission to do any operation yeah so the next step what we can do here when we call the mutation function we can add as the the first one is the data the variables the second one is some additional options and one of the additional options that we can uh specify here is the on success basically this function is going to be called when our mutation is executed success UC F so what do we want to do when on success only then we want to reset the fields and maybe even using the router to navigate back so do we have a router here no we don't have a router but we can get access to the router using use router Hook from export router and after the product is inserted successfully I can do router dot back so going back to the admin if I go here and say one 2 free create after it is executed we are redirected back to our menu and in our menu we don't see a newly created up if I'm going to refresh it's going to be there yes it's here but we would like to see it right away how can we do that we're going to do that by going back to our API products and the same on success function we can Define here when creating the mutation we need it here because it's the right place to do these kind of things that we're going to do in in the next moment so after the a sync mutation function we can also Define another function called on success that is going to be called when the function successfully executes what do we want to do when this function successfully executes in order for the item to appear on the first screen remember the first screen here is our index that uses the use product list the use product list is here if we scroll up is is this query so what we can do is we can tell our react query invalidate or refetch the query with a key products to do that first of all we need access to the query client we can get access to the query client in our insert product Hook by using the use Query client imported from the T react query now having access to the query client on the own success we can use it to invalidate queries with the key the key that we want to invalidate for example products and we can also probably await and the same way as you have one success you can Define other functions for example on error and here you're going to receive error and maybe log it in your um somewhere or do something about it or show an alert I don't need it any error handling here so now if I'm going to go to create a new product new product one two three if I'm going to create it we're redirected back to the menu but as you can see it already appears here so it automatically refresh the products and in fact it will also refresh the products on the user side on the same device basically because it uses the same key query so that's why we are defining the query key to be able to Target refetch them when something happens in our application in our case when we insert a product we want to refetch the list of products because we know that by creating one we will update the list requery will invalidate and what it does actually behind the scenes it fetches the query again it executes the select products again so that uh is it with our inserting a product this one is going to be updating a product yes let's start by creating this use product export con use update product equal to a function and the use update product will look very similar to our creating a product so let's copy everything from inserting a product in our update and do a couple of changes first of all let's look at the super base what do we need to update a product well instead of insert we're going to call the update the update will contain all the data from here from data name image and price but we want to update based on the equal operation we want to update a specific item and the item is going to be the one where the ID matches a specific ID whenever we update an item we will know the idea of that item so we're going to send it here through the data and we can access it as data. ID then we can probably select and do single here uh not new product but updated product let's return Advent updated product and on success which query should be invalidated here well we will invalidate the list of uh products because one of them will be updated but we will also invalidate the query for details of one product so use product with ID so this query key will also have to be invalidated to be updated but we don't have access to ID here well we can have it as a second parameter in the function parameters so here is going to be our data and we can access it as data. ID or you can right away destructure it from here as ID now let's go ahead and use this use update product hook inside our admin menu create similar to how we have the insert product we are going to have uh use update product and here let's rename it to update product I want to do the same trick here with the ID I want to first of all take it as a string I'm going to copy it like this I'm going to take it as a string and I'm going to par it to a number now now what's left to do is to call this update product function on update so on update let's call the update product with the data about the product for example name price might have changed uh similar to how we have here for inserting and image but besides all of this data remember that we also have to pass there the ID for the data ID so the ID is going to be be the value that we parsed above here update product we can Define the same on success logic as the second parameter so when uh the product is updated successfully we're going to reset the fields and we're going to do router. go back so if I go to the admin and we're going to try to addit pepperoni to something well actually I forgot something the thing is that on the update screen when we are trying to update we also are quering the details of a product so for that reason we need to query that details of the product that we want to update so for that we're going to use the use product use product and the use product hook requires the ID we're going to give the ID that we received here and let's take data as updating product or something like that updating product now this updating product when it changes I want to update our state variables to reflect like to set the name based on the product that we want to update so in a US effect when the updating product changes so we're going to add it as a dependency what we want to do is if updating product then we want to set the name using the updating product. name set the price using updating product. price and what else we're going to set the image with updating product. image and now if I'm going to go to edit the pizza paperoni it should fill here with the details but it doesn't why we can have a look at the updating product uh information so it it has it there but it doesn't call the use effect it doesn't go into this set here oh I have a mistake there but what about the price maybe it should be to string yes price to string worked so now if I'm trying to edit it it will be prefilled with the values of the product that we want to update perfect and let's see pepperoni one to three if I press update it goes back it updates here it updates here and if I'm going to refresh will it still be there yes it's there and if I change the price to something like that there is a small issue and I know why uh that's happening in the on update create we should only reset the fields when the success comes and we should remove it from the bottom of this function and this way we can update it update and we are back to normal so that's our onupdate function wait a second why is this function called called on update create think I wanted to call it on simply on update let's double check the on create as well Ah that's what I was afraid of cannot convert undefined value to object I think it's coming from a missing ID here so I'm going to add a question mark do dot when accessing the array and now if I'm going to go to admin for updating what's happening new let's try to update it yes it works yes uh so our update a product is finished and with that being said we have create we have read we have update and probably the last one is that delete a product let's go ahead and implement this together and we're going to start with a mutation in our API product called export const use delete product equal to mutation so I'm going to copy the top part here when deleting amutation where is it it needs one more yeah when uh trying to remove something from super base let's go ahead and do a wait superbase do from product what we want to do is we want to delete and it needs well it needs I think a logic here at equal where ID is equal to ID that we will receive as number so ID column ID is equal to Value ID Let's uh have a look at uh super based documentation and I'm going to show you how uh easily it is like you go to a table and you check the API documentation here and here are some already predefined uh queries that you can run I'm going to scroll down until I see the delete rows uh yeah the equal should come after the delete so equal call should come after delete okay so I'm going to have it as simple as this maybe we can also add the on success what should happen on success we should use the query client to invalidate the list of products so yeah it's also going to be a sync and let's use it in also in the admin menu create when we are trying to delete I mean on the update product there is the delete button so so let's import it here const mutate delete product equal use deete product now we're going to call this delete product function in the on delete here so we need to call it we need to send a variable ID which will be our ID number oh it doesn't even have to have an object it can be simply delete product ID and as a second parameter on on success what we can do here is reset fields and router back on success it's a function and I don't even think it should be router back because we are it's going to redirect us here router maybe replace to the admin side because we know that we are on the admin side here so if I'm going to go to the hey edit press on the delete confirm we should be redirected to the home screen if there is no error and now the hay is not here the same thing with one 2 three we can go ahead and deleted uh Json object requested multiple where no rows returned yeah make sure to also take the error and do to throw it if that happens let's go ahead and uh commit all the changes this is our product crude all right guys so with that being said we have have all the crude operations for our products so it was a very long tutorial but now we know how to work with superbas to manage the data in our database we know how to work with react query to query and mutate our data cach it invalidate the queries manage the loading States and all of the good stuff when it comes to working with remote data in an application and implementing crude operations all right so uh previous lesson we have implementing the product crude but if we go back to where we used it for example if we go into the user menu index and we check what is the type of our products we see that it's of type any array of any or even undefined so that's no buo whenever we see that any keyword when using typescript that's a red flag and we need to go ahead and probably type properly our used product list the used product list is a used query and it's using super base and even super base doesn't know what type uh is the items in the product the best part is that we can generate types automatically from our superbase database schema and use them to type the whole superbase interactions in our application so that's what we're going to do now we're going to configure the typescript uh integration with super base one way to do that is going to be to download the types if you go to your tables to any table if we go to the API and scroll down there is the generate types and you can download these types here what I'm going to actually show you is how you can do that from the terminal using the superbase CLI let's go ahead and start by running npx super base login in a terminal so I'm going to go ahead head and log in here and super base will ask us for an access token we can generate that by simply opening this URL here and uh on that page you will be able to generate a token simply press generate token copy it and paste it back in your npx superbase login uh I'm already logged in so that's why I'm not doing it but now we can simply run a command with npx super base to generate the types so let's copy this command from here let's paste it in our terminal but before running it let's go ahead and change the your project ID here with the actual project ID of your application so going back to super base if I'm going to go home and maybe the project settings here we're going to see reference ID which is the project ID or you can look in the URL in the URL you'll also see the project ID so let's put it at as the project ID and what we are doing here is we are generating the typescript types and writing them to a file called Source database. types. TS after a couple of seconds we have a new file database types which was generated based on our tables as you can see we have our public schema tables including the products and profiles and for every single table there are information about what is the data type also what is the data type when we're trying to insert when we're trying to update and so one so these are very helpful types that we can right away use inside our lib super base to specify the types to send these types to our client now superbase doesn't know what types it's using so let's go ahead and simply import database from database types and send it here as a generic to the create client as database just like that if we're going to go for example in our API index when we call super base from products if I will hover over the data it already knows it's not any anymore it already knows the actual data based on the information from our table from our database so next time you uh update you add new tables go back and run the same npx super base gen types typescript with your project ID to update your types and they will reflect in your application now uh let's see if the use Query will also for example if I go to API user menu and if we go to the index here will the products be typed yes the products are properly typed automatically by simply sending this these types to the create super based client the item is automatically and it matches the the types that we have perfect so uh what I also want to show you here is how you can Define some helpers because whenever you will want to specify that something is should be of a product or profile type it's going to be quite hard to access it just because of the way these types are structured so you're going to have to access data public tables products row instead of doing that let's go ahead and create some helpers and I'm going to do that in the actually let's do that in the types. TS because types. TS is the file with the types that we Define in our application and later we're going to have to remove them but for now let's just simply at the top here Define some helper types for our database let's just simply copy them from here and and I'm going to show you how they can help us for example now what we can do is let's go into the components and let's say that our product list item I don't want to type it manually as I have done it so far we did we have done that because before we didn't have super base in our stack now that we have super base I want to say that this product should match the type of a table from super base if we look in the database it should match the public tables products and the row specifically but with this helper tables type that we Define here which looks like a lot of magic we can easily type our uh product list item here not with product but with tables and here we can specify which table it's the products table and just like that we don't need the product type anymore that we Define manually and this will come directly from our database generated types yeah we can change that uh we can look in other places in our application where we are still using this product type uh in the card provider let's have a look at the card provider so the card provider will receive not a product that we Define but it should receive a type of tables products it's here as well so what I can do is simply say type product equal to this tables product and then leave everything else as it was and remove the imported product all right so I'm not going to continue I I'm afraid to confuse you too much but what we can do here is we can use the types generated automatically by super base to make sure that we are using yeah like we are typ typing the things based on the data that at the end of the day will come from the database so instead of specifying it manually like we did before we are using this helper function table that gets us access directly to the row here so that is everything about the typescript integration with super base let me go ahead and do G ad super base typescript all right so we in the previous lesson we implemented the product crude and the typescript integration now let's go ahead and implement the crude operations for our wers because in our application uh besides looking at the products you will also add them to card and whenever you press the checkout we want to record this order in the back end and as you can see the order will include some product but not directly product it will be order items because besides the information about what product are you ordering there will also be information about the quantity and the options that you selected so let's start by designing uh our tables in super based dashboard and we're going to start with the order item if we look in our hand uh written types uh we specify that a order will have information like ID created that which will be generated automatically but besides it will have a total and a status the total will represent the amount which can also be calculated but maybe we can uh write it directly in the in the table and also an important thing is the user ID because we have to know who placed that order and where basically to deliver so with that information let's go ahead in our superbase dashboard and we're going to go to our database in the tables let's go ahead and create a new table and call it wers we're going to have a row level security here and uh for the columns besides the ID and created that as we said we will also have status which will represent the status of a word it's going to be a text and we can also set a default value uh we're going to set the default value to new and whenever we do not send a value for the status when creating an item it will uh initialize with a new and we can said that this is a required field so I'm going to deselect the nullable the total will be a number or actually a float we can choose a float8 maybe there will be like very huge orders and the initial value we can set it to null and it will also be a required field going back to our type here the last one is the user ID and the user ID is our uh the way we are going to connect the word with the user so it's going to be called user ID the user ID is going to be the field that will help us create the relationship between an order and the user in relational databases there are multiple types of relationship between tables the first one is one toone relationships and a onet toone relationship it's easiest to explain using this relationship between the off users table and our profiles that we created so here we have a onetoone relationship between one profile belongs to one single user and nothing more if we think about the relationship between orders and uh users one user will be able to create multiple ERS and if we invert the statement one order will only be created by a single user or will only belong to a single user so this is a on to many relationship and a relationship like that uh is defined using a foreign key on our orders table for example so the user ID will be a relationship here we're going to select a table first of all select the schema public and then the table so we're going to connect it with our profiles table and we know that profiles will also be connected with off user but in general like everything in our application when it comes to the user is going to be managed in the profiles table now we can select the column from profiles and that's going to be the ID and uh the action uh is also important to specify because if if an order is attached to an user and the user is being deleted what should happen with a Ard so with uh Cascade whenever the user is deleted all the ERS assigned to that user will also be deleted automatically and I think that's the most appropriate one uh here so what else do we need to specify here oh it says that the column time don't match it should be a uu ID so let's uh first select the type as uu ID and then we're going to connect it with our profiles ID and select Cascade deletion now our table is being created but as I said besides the table that will hold the information about the wers we should also have another table that will hold information about the order items and the order items yeah will have a link towards the product that was selected quantity and size here we can see the type that we have with product ID with order ID size and quantity let's go ahead and create that table as well uh it's going to be called order underscore items and we're going to go and add columns first of all it's going to contain the product ID relationship so this is going to connect to our products by ID and it should be of type B so int 8 select that and after that we can create the Define the relationship ship and here as well because our order item will be linked with an order if a order is deleted what should we do with order items I think we can also delete them as well so let's save this relationship and what else besides product ID the size that was selected so let's add the size here of type it can be text and it's going to be required the default value we can set to M what else quantity quantity is a number and it's going to be an INT for non-nullable and it by default it's going to be only one because if there is a link to the product we assume there is at least one product there and let's double check that with the screenshots from here and on the right we have the product ID size quantity and also the word yeah that's very important word item should also have a relationship with the order in which this item was added so here we're going to select word ID it's going to be of type integer 8 and we can connect it with our order by ID and whenever the order is deleted we're going to delete the order item as well and we can also probably put that product ID and Order ID as required Fields because we them it's going to be useless so with that being said we can press save and we have our two new tables created ready for us to integrate and save information there if we look at the schema visualizer our datab already looks more interesting we can move things around and we can see the relationship between all of them starting with profiles that will have wers the order will have items which will include products so this way we will be able to manage all the ERS that users create but before we do that we should also make sure to add some uh policies to our newly created tables so we can go to the table editor and under awarder we can select here view policy and we can create a new policy to allow all operation for authenticated users and here we can just say true and true actually here yeah like it it's going to make sense to allow uh operations like update and delete only to people who uh created the order but we will also need it for the admin so admin should also be able to update okay never mind let's just keep it simple and allow any authenticated user to perform these actions review and save policy and we should do the same for our order items view policy new policy and let's uh customize it authenticated and here true true review and save policy all right so we are ready here on our superbase dashboard let's go ahead in our application and start integrating with our super base to create read update and all the rest of operation ation that we need to do on the wers and Order items all right so let's go ahead and follow our guide and the next step is going to be to uh read wers for that we're going to need some information in our database so let's open the wers table and insert something here for ID and created that that's going to be populated the status as well it's going to be defaulted to new the total let's say one two three and we will press here select record to connect it with a user at the moment we have only one profile in our profiles table so that's why we only can select from that one let's press save and maybe we can create a new one we can override the date for example to 2022 and the status can be delivered and the total 50 and also connected with my user id save let's also add uh another profile in our profiles page let's connect it with a Damia account like with this a and for the group it's going to be user I think everything else can remain the same I just need one new uh user to create an ID that will not be mine to be able to filter properly them wers only that I created so I'm going to create a new one and Link with this ID ending with CC let's go ahead in orders and create a new one uh the total is one and the user ID is the user ID ending in CC with second one now we have three orders uh two of them are mine and one of them is linked to another user let's go ahead in our application and implement the read operations for our orders similar to how we handled uh the crude operations for product we're going to start by creating a folder in the API let's call it orders and let's start with the index.ts file and here we're going to have probably a look at the index from the product to see how we implemented the read operations a lot of things are quite similar so it's going to be easy for us just to copy paste and adjust the data that is being requested for example use product list this is the one to read a list of products let's take it in our wers file and adjust it to instead read ERS list I'm also going to copy the import from product here like this and uh let's go ahead and change our query first of all it's important to update the query key here we're going to work with wers so let's call it wers and we're going to query from super base the table is going to be called orders we're going to select everything and return the data as we can see the data is any because if you remember if I have here products superbase will be smart enough to understand with thises of type product because we have the types defined for the product tables now we added new new tables but we didn't regenerate the types and that's why when quering from ERS table uh superbase doesn't know what type is the data in that table so what we have to do in order to get fully full types anytime we do changes on our database layer we have to regenerate the types again so I'm going to scroll up in my terminal until I find the command for npx super based gen types and I'm going to run it again this should go ahead and regenerate our database types and if I'm going to look here in the database we already have a order items and the ERS row and automatically super base should be able to yeah understand the types that we receive here perfect so now uh it's going to be easier for us to integrate with this use product list yeah we need to update the name use admin order list because only the admin will query all the orders from the database let's call it like that and and go ahead open our application admin orders list index and here I'm going to also open the screen on our device let's go to the admin side orders and here is the index screen the active wers let's go ahead and use our newly defined hook use admin order list this one if you remember from the previous lesson will give us the data which will be our wers it will will also give us the is loading and the error what we can do with that we can simply follow the same approach if is loading we're going to render the spinner the activity indicator if error we're going to say fail to fetch otherwise we're going to render the flat list now we can safely remove the orders from damid data and the ERS should show from the database let's go ahead to the orders Tab and we see three orders 1 2 and three and this is exactly word is coming from our database that we defined here perfect so that is reading the list of ERS let's go ahead and see how we can implement this on the user side on the user side we don't want to query all the ERS we only want to query users wers so actually instead of filtering probably I'm going to Simply create a new hook here in our API called use my order and when doing that because we are defining all of this data fetching mechanism inside custom hooks that means that we have access to other hooks in our application such as use off and using the use off we can take the information about the user or about the session and the session has ID equal session. user ID uh yeah let's go ahead in our super base from or orders after we select we should also Define a filter we want to make sure that the column user ID equals to the ID of a user that makes this request but we see that this ID can also be undefined so before we execute this super base function we're going to check if ID is undefined let's simply return null but it shouldn't be undefined when we get to this page because at that point the user should be in the session and and because this query we don't want to keep the same key for this query because it's going to contain different data it's going to contain filter data and now we have the same name for the admin orders and for my orders so this can mess up how the items are cached behind the scenes in order to make sure that my orders are store separately from the admin orders let's go ahead and add as the second parameter an object with user ID and there we're going to specify the ID from here now we are ready to integrate this use my order list inside our user orders index so let's go ahead and most probably it's going to be the easiest to look at how we used the hook in our order screen from the admin and simply replicate it in the user side the only difference is going to be the hook that we are using instead of admin order list we're going to use use my order list list and here activity indicator now we can remove the damid data and go to the users to see if it's being correctly filtered as we can see there are only two orders the ones uh connected with my my user and if I go to the admin side the admin will see all the orders all three of them perfect if I look here there is a typescript error saying that order list item the order that it expects is something different and that's because the order list item is still using the handwritten order type here what we can do instead is use the helper tables and specify that this order is coming from our database tables ERS now we see that inside here like when we access order ID and so on created that typescript is not complaining so that means that we have these fields and if I go back here in our list typescript is okay with this as well so this was both of our list but actually in fact I want to also show you how we can add additional filtering and because on the admin there is the active and the archived wers so for that inside our wers API where we have a admin word list it's either we also like duplicate this two times or we can add some options here based on which we're going to filter and send the super base request and the option here is going to be a b field archived and if that is false we're going to query active orders otherwise we're going to query delivered orders so we saw how we can use filterings like equal but in this case as I said the based on the archive we're going to have a an array of statuses we we will want to filter on the status order so on the active we want to display all the ERS that are new cooking and delivering so for that we're going to use uh includes or in an array operator but for that we need the the actual array so let me show you actually how it first works for example if after select we will do in we will specify the column the column is status and uh as the second parameter we're going to provide an array of values for example new and cooking and also delivering so if I go to the admin orders cannot read property arived of defined well yeah because when we use the use admin orders in our list we need to send here whether it's archived or not so here on the active is going to be false now we can go there to the admin orders and see that fail to fetch data why well we can go ahead and see the error admin wers no everything is fine so as we can see it correctly filters the order and doesn't include the delivered if we have here also the delivered we're going to see a new order pop up here why it's not delivered oh because it's all capital yes now all of them are here so as we can see we can uh filter based on an array of values and we're going to get only the ERS which status is inside this array now based on the archive let's go ahead and define basically the array of statuses that we want to filter on so statuses is going to be equal if our archive is true then it's going to be an array of only the delivered otherwise it's going to be the rest of the values now let's use these statuses instead of the hardcoded array and it is going to depend on the archive or not now to see an actual action let's first of all see it in if the active tab is working active tab is working and if I'm going to go to the list archive let's also query here data using the admin word list but on this screen we're going to say I want archive to be true let's import it and activity indicator as well now if I'm going to go to the admin here we're going to see the active orders that are in new cooking or delivering and on the archive I'm going to see only the new but it doesn't work you know why because we are using the same key for the admin W list in both cases where the archive is true and false that's why it's overriding the query so here is a example when you forget to specify the proper query key because here the query also depends on some variables like whether it's archive or not so if by simply adding this to the array of query key they will be stored separately and as we can see it works properly on the active new new here is delivered and that's how we can filter and read our wers perfect moving on to the next step in our read we're going to go to the read order by ID let's ahead in our application and reading an order by ID is again let's open our API let's open both orders API and product API in products we can look at the use product we can copy it in our orders and adjust it for our use case let's rename it to use order and we can probably be more specific because use order is very general or maybe we can do use worder details uh it's also going to receive an ID number the query key will be orders and the variable ID we're going to fetch from orders we're going to select all the columns where ID is equal to the one that we're requesting and yeah now it's ready to be used in the detail screen both on the user you go to the orders ID here instead of finding it manually what we're going to do is we're going to receive it using the use order details we need to send here viid but the idea again is this problem with string that has to be pared to a number so let's actually look at how we did that here in the menu item with pars float and ID as a string I'm going to copy these two lines and I'm going to add them at the top so we first take the string and then we par it to float depending on on the type now user ID will give us back data which is going to be our worder it's going to be is loading and error with this we can uh do the is loading activity indicator and the error and I think we can remove this to blocks as well yeah the D data as well we did that in the user side so if I'm going to go to the user side and click on word one yes it works and here as well works perfect let's do the same so I'm going to copy the whole body of a word detail screen and let's put it in the admin as well as admin orders so at the top instead of this body I'm going to use the one that we had there make sure to import but use order details and activity indicator from react native and make sure to test it always test it as go to wers if I click on one of them we see it properly and if I go to the archive it's also going to display the proper status here based on the one that we have in the database the next step is creating orders when should that happen if I go to the user side application we're going to be able to add things to the cart and when we press check out we want to First create the order and after that create order items and Link them to the order let's go ahead and do that starting with creating the order and we're going to do that in the orders having a look at how we did that use insert product so let's take the insert product in our wers and see what we can we should change starting with a name use insert order let's import the query client at the top from react query we also need to import the use mutation this is our first mutation for the wers so what should happen here mutation function we'll receive some data that at this moment we typed it as any that's not exactly what we want I think what we want is somehow to say that data is of type tables orders right yes and no the table do ERS is also going to include the ID also going to include the created ad if we look in our source the hel tables will access the in the last place there is this row so if we look into the database types for example for orders this orders table has multiple types here for example the row will have this type but when we have to insert we can use this type which has the optional ID optional created that which are uh have default values and actually all of them are optional you see so we should somehow access this type instead of a row type to do that uh let's go ahead in the types and maybe duplicate this tables helper type let's duplicated and call it insert tables and from Row from row we're going to change to insert now if we use this helper in our function instead of tables let's see what do we get if we hover over the data we see that the ID created at are optional so what we can do is simply say that we want to insert the data here why superbase doesn't like Yeah because it should be in the wers table Yeah you see how smart it is like it detected that we're trying to insert orders into a product and it's told us so that's why we need to change to wers and yeah I think that's what we have to do here but as you can see there are for example this user ID we are not going to want to send this user ID I mean we can send this user ID to the data when we call the mutation but another way is we can also because we have access here to information like use off we can automatically take it from here so let's take it as session and the user ID is going to be equal to session. user. so when we insert a data we can override we can dist structure all all the data and at the beginning we can say that the user ID is equal to the user ID from here this way we will not have to send for data a user ID but if we will send it's going to be overridden so I think it's better if we make sure that the value user ID from here takes priority and will override anything that will come through the data okay so I think we are ready to import this Usinger word in our card and start using it the logic where we will call all of this remember we had a provider that has a responsibility to manage the card this is the card provider I think this is the place where we will also call the create word function so what I'm going to do is I'm going to export from this uh provider a function called checkout this is going to be a simple function it will not return anything and we can Define it here as is an empty function but in our car provider we can implement the logic uh what should happen when we call the check out first of all start with a console warrant to make sure that at least uh we we call this function when we press on the checkout button now export the function checkout for our value and on the checkout page we can link the Press of the button to this function let's find the checkout page in our application cart and here we have items total and checkout from the card now when we press on the button checkout on press let's call the checkout function from our provider now if I'm going to press on this button we see check out perfect so uh what we have to do is go back to our car provider and in the car provider import our API function use insert order and insert it when the checkout function is being called so card provider at the top we're going to Define our hook here and as you remember the hook will return the mutate which we can rename to something that will make more sense like insert order now this is a function that we can call to trigger the insert order operation so let's do that here we need to send the variables even though we don't have to send actually anything because all of them are optional I think we're going to send the at least the total now if I'm going to go to the user remember that now in our database we only have three wers if I'm going to go ahead and go to the card and press check out nothing happens but in our table we see one more word perfect what we can do here actually is we can add a on success and what should happen on success do we have something like reset items or something like that where we can add it here as clear card which can set reset the items from the card to an empty array so on success we can basically clear card and probably do router go back if we have a router here we can get the router from use router import it from export router and we can simply go back when the order is placed by doing router back actually not router go back you know why because we want after placing an order we want to go to the detail page of a order so what we can do is router Router push to the order with that IDE so it's going to be slash user slash ERS slash and the ID of a order but how do we know the idea of a order will we get it here on success data the data will contain something data dot let's look in our card provider what are we doing here yeah we're actually returning the new product data. ID what that will be let's simply console log data to see what values we have so let's go to the user create a new product it's null let me look in the products real quick cuz I remember on success we we can take yeah uh is it because we didn't provide the return function the new product is never actually because we need do we need select afterwards to get it back yeah I think without select it will create the order but will not return it back now we receive it here and we should receive it also in the own success yes that means that in our card provider we will also receive it as data and it will have data ID so let's double check if that's true if I create I expect to be redirected to the newest order created a few seconds ago to The Details page yeah that's exactly what I wanted to do so uh so far we are uh correctly creating wers but we lose some very important information from the order the items that have been added there because I add here items I create the checkout and we only create the order the next step is to also after creating the order to also create order items and Link them to our order for relationship for that in our API let's go ahead and create a new folder for order items let's go ahead and start with index.ts and based on our guide what we need is to create order items create helper function to create order items okay I think we're going to take the insert operation from orders and work based on it so let's take it from here let's also take the Imports and see what we have to do insert order uh we're going to rename it to insert order items it's going to work with order items table it should be order underscore for items the table is going to be order items the data that it expects it expects order ID which is not null it expects product ID it expects quantity size so there is no data that we can take from here somewhere that's why we don't need even the user ID that's not a field there and I can remove it from here now let's go ahead and try to call this function and we're going to do that also from our card provider after we insert the water knowing its details we're going to add to that water a list of uh order items let's define here a new function called save order items and this function is basically going to be our own success here should we simply yeah take everything from here put it in our save order items later we're going to think where exactly they should be called and the data as well here and the save order items will be the function that is being called after the order is successfully inserted the data we can also save it is going to be of type tables and it's going to be orders let's call it order actually so let's go ahead and import our uh insert word items mutation the similar way how we did this one insert word items insert word items now we're going to call the function make sure to import it we're going to call the function in the save order items so insert order items we'll insert data so what information does it need well let's go ahead and just take one item from our list of items in the card and try to insert that one and see if it at least works and then we're going to think how to insert multiple items so the data what does the data need word ID and product ID well word order ID we can take it from the newly created order do ID product ID is going to be our the item from the cart do product ID and that's the only thing that is required let's see if we need anything else quantity and size that's also important so quantity item 1 do quantity and size item 1 do size so let's see if at least one item is inserted but uh we don't want to redirect with a r and clear the card before we finish inserting the order items as well so for that reason we're going to add the on success here the on success and only here we're going to clear the card and uh navigate to the order ID so let's see if at least one item is being added I'm going to go to the user let's select Margarita let's select large and press add to card then quantity two and check out we get on the ERS page even though we don't see the items yet let's see in the database if they are recorded so I'm going to go to the order items we see one created uh just now for the product with ID one which if you go there it's the margarita and size L quantity 2 and word ID 10 exactly what we needed so the item is being Sav correctly now the the next thing is how we can insert all the items from the card if there will be more more of them we can do that uh because if I'm going to look in the API where we use this super base when inserting something we can insert a list of items by sending an array the data here let's say that it's not going to be a one insert table but it's going to be an array of them and simply instead of D structuring of course we're going to say data or let's call it actually items it's going to make more sense now these items let's see in the car provider when we call it insert order item now doesn't expect one object like this but it expects a list of items order items equal to the items from the cart if I simply do that it's not going to uh exactly work let me comment this out order items it's not going to work because of it types in the card these are card items and we don't have like the right types and we don't have a word ID so I'm going to have to map through them through the cart items cart item and for every card item I'm going to create this structure of object every word item should have a word ID product ID quantity and size and now typescript is not complaining because the types are matching exactly what we need so if I'm going to go to the user and select Margarita use card is not a function what happened oh I have a bug actually I'm taking the information from item one I don't even need the item one anymore I'm going to take it from the cart item just like that and let's give it a try with this new approach of inserting an array of items let's go to the user side add some pizzas and press check out Jason requested what multiple or no rows returned oh yeah because in our mutation here I said it single which will take only one item will return one item back when in fact I should have an array of items here so give it a try again pepperoni L and one pepperoni M which are two product items check out and we are on this order if I look this is the order with ID 12 the total is correct and W items there are two of them and both of them are linking with the word ID 12 the quantity is also correct and the sizes perfect so that means that we are correctly creating Word items and linking them with a newly created word and after that we are simply redirecting to The Details page going back to our apis uh here remember to update this on success message because it should invalidate the right queries it's not going to be a problem but it's inefficient if you are creating order items but invalidating the query products which has nothing to do with this so in this case I don't even think that we need to invalidate any query so we don't need a query client we can clean a little bit here and the same thing in the orders let's see what we invalidate when we insert an order we invalidate products when in fact we need to invalidate orders this sarey orders we are finished with reading orders and uh creating ERS creating order items on their reading side actually something is missing if I'm going to go to my orders to the latest one 12 for example let's go ahead and order them chronologically based on on the ERS that are most recent I want to display at the top to do that we can do we can specify the order in which we want to sort them when we query them from super base let's go to the API orders index and in the my order list we can after equal we can say do order and we specify the column that we want to order based on we're going to use the created ad and we can say that it's not ascending by saying ascending false and that's going to be the most recent first so if I go to the user orders I should say yes the latest here at the top and we can add that as well to our admin orders for the admin to also see the most recent orders at the top and remove this from here and if I go to the admin orders he should see the newest one at the top perfect but uh I actually was looking for something else when we query the details of an w we will also need information about the ward items because at this moment we don't have that even though we have if we look at for example application admin or there Details page we have a flat list there with a list of order items yeah the problem is that we are not querying them yet what we could do is to add a query here in in the order items to get a list of items based on a order ID that would work uh but that would require one extra query in our application what we can do as well is whenever we query a word so let's go to the order index when we query the details word details we can also include fields of items related to this word we can do that by specifying in what columns we want to select a star means all the columns from this table if you do a comma and here specify a table related to this which is called order item items let's do select order items and here you can also specify which columns from V I'm going to select all of them and this way let's go ahead in the admin order details and query the information about the order here not query but console log and let's see what data we have there so if I'm going to select the latest order uh we will see some issues but we will also see that in the data besides created that there is also Alo an uh a field order items which is an array of order items the problem is that an order item does not have the image of a product because the the information about the product is not in the order item table in order item table we only have product ID so the product is a relation of the order items what we can do is also in this selection field of order items add another comma and say that from the order items we want to access the products as well the name should match the name of a table products and we're going to select all the fields now if I'm going to go to the admin and check the order with the first one here we have it now it works and now we see a list of product items with the information like quantity is coming from order items the size is coming from order items but the name and the imag is coming from the products so this way you can query nasted data in one single query with super base I think that's really powerful and it should work on the user side as well yes it works so it has this order items here so it knows that it will take it and even products but when we get the data yes it has but here order it also has order item so what's the problem flatlist order. order items so order is pro possibly undefined that's why we can make sure that it's not Define by adding in the error here if error or if there is no order then there is a problem now order items will be okay and to make sure that we get rid of this typescript issue let's go to this component word item list item and change from the handwritten type to the tables helper type and here we're going to specify order items well we can say that this item we are sure that it's going to be not only information about the word it item but actually something additional by doing that we're going to specify that it will also have products of type tables products so besides the fields from the order items it will also have a products because that's what we are querying here all right perfect with reading we are definitely finished we learned also additionally how we can query related data now let's see the update order because admins will have a possibility to update the status of a order so let's go ahead and create this mutation in our API orders index TSX so going to API wers index we want to have a update mutation let's look at the how that was implemented in the product use delete no we're going to look at the use update product let's copy this one from here and see if we can if it will help us implement it faster so let's start with use update order updated order super base the table is going to be orders what we're going to update well let's specify the data that we want to receive here by taking the insert tables the orders but not insert you know this is an update query so if you remember the besides row and server is also an update so I think we're going to create another helper type that will give us access to the update type by specific here update at the end so the data the input will be of type update tables and here we can put all the dot dot dot data or actually we don't even need the the object we can just do data but the data will will it have ID the data has a optional ID there but whenever I update the the table I need to to have a required ID so what I'm going to do is probably instead of having only the data I'm going to have two Fields the ID and the updated fields and the type is also going to be an object the updated Fields will be of this type and the ID will be of type number now instead of data we're going to take the updated Fields instead of this data. ID we're going to do ID and we're going to return the updated word now on success we're going to refresh word ERS and also the orders by that ID because we're going to update an order with ID and we want to update it in cach as well whenever we use this query so uh with this let's test it out we're going to import it where in the admin side in the order details no this is product details order Details page here whenever we press on this cooking or when we're trying to change the status we want to change the to update the order so let's go ahead in our application admin wers details here we're going to need the update order then M mutate we're going to do update order and whenever we press on one of these statuses uh let's go ahead and call a function a function update status where the status let's simply create this function connect it with the status list and make sure to send and the status that we're clicking on let's see what type it is word status hm not sure now when we call this function what we want to do is we want to call the update order function and send their uh variables it needs the ID and it needs the updated field updated Fields probably is going to be a better name so sorry for that but I'm going to change to updated fields and yeah let's send the ID what id this ID and updated Fields will be only the status that was passed here now I think it should work let's go ahead to the admin let's look at one order let's change it to cooking and it's not like instant but after that change is saved because we are invalidating queries the change reflects automatically so if I go back we see that this one is in delivering order 12 but if I will put it into delivered uh if I go back it's not displayed here but if I go to Archive it's already here in the archive and yeah it works properly to to update the wers it updates correctly and it's also going to be displayed on the user side as well so with that as we can see we are finished with a crude operation for the wers and W items I know it was long but hopefully by repetition by doing it multiple times now it makes more sense how we can interact how we can Define this API calls and how to better structure everything when it comes to managing uh data with superbase all right so now that we have all the crude operations for wers there are situations where we want to update users whenever some data changes for example in our application I would like the admin to receive the new order as soon as someone places it in order for him to to be able to accept it and to start cooking without having to restart or refresh the application on the other hand on the user side I want us to implement realtime data whenever the user is waiting for his order I want to update the status as soon as it is updated in the database right now we would have to refresh or go back and come here to see if it if it was updated so here uh is where subscription will come into play and will help us listen to updates and do something when this happens so let's go ahead open the real time data with subscript and the first step that we have to do is to enable subscription on the table that we want to uh listen to updates uh the real time is not enabled by default on all the tables but we can enable it easily through the dashboard let's go ahead in our table editor and the table that I want to listen to update is in the wers because whenever a new order is inserted I want to update and when he's it is updated as well so let's go ahead and click on the Ed edit table and here enable real time let's select that and press save just like that now we can start listening to realtime updates for the ERS table if you look at the API here you can already scroll down and see some real examples of subscriptions so I think it's the almost the last part with subscribe to changes so if you simply copy something from here it will work let's see which one do we want to copy I think we want to subscribe to insert events on the admin side so let's go ahead and copy this one from here which you can also find it in our uh guide let's go in our application and think where do we want to subscribe to insert updates we want that on the admin side when he is on the orders page here let's go ahead in our application admin and that's going to be for us the active tab of our order list so order list index when he's here I want to subscribe to new changes when do we want to subscribe as soon as this page mounts so for that reason we need a use effect that will have empty dependency list to make sure that we subscribe whenever this component mounts I'm going to Simply paste the subscribe to insert code snippet from here let's put it here and see see it in action we need to import super base here and yes event insert schema public table orders and we're going to Simply conso log with payload let's navigate to that page and let's open the terminal I'm going to clean it a bit and let's go ahead from our tables insert and Order manually let's insert and I'm going to leave everything by default save a new order is created and if we look in the in the terminal we see change received with the event type insert and there is a filled with new that actually has the data about the newly created word so we can take this one and add it into some State variable to merge it together with our words is that are already queried another thing that you can do instead of saving like this new data that we receive in state is simply invalidate some queries that will trigger a refresh so using the client use Query client from t that query import using the query client when we receive the insert update I can simply call the invalidate queries and which ones the ones that are responsible for this query so or if I do orders this will actually invalidate all the queries that starts with orders so if we look in our API orders this will include the admin orders this will include the the my orders and so on so let's see if that actually works I'm going to bring the emulator close to us here and we can create insert a new order here and see it automatically appear without any refresh right away order 14 a few seconds ago appears on the admin side if I do it again as soon as it's saved our list is updating to reflect the new change so yes one way is to receive a payload and using it to save it in a state variable and then merge that's a bit more complicated but it will not require an extra query with invalidate queries this is the easiest way because we just simply invalidate and let R query refetch all the queries that starts with wers and this way we have the the changes there right away but whenever we are uh subscribing to data changes we should also make sure to unsubscribe we can do that using the return statement here we can call it wers subscription or something like that and when we if you return a function from a use use effect this function will be called when unmounting the component and here is where we can clean up all the subscriptions and so on so we can call unsubscribe just like that to make sure that we don't leak memory I would go one step further and extract this subscription to our API orders maybe we can create a new file here subscriptions. TS and let's call it export const use insert order listener or subscription this is going to be a custom hook where we can put our use effect like this we have a query client as well so let's copy it here and because it's a custom hook it's going to be able to use other hooks like us fact use Query client make sure to import it from T query we don't need use mutation we don't need this one we need this super base and yeah that's probably it now the last step is to go back in our index screen and use our custom hook called use insert order subscription just by calling this uh subscription it will subscribe and perform like invalidate query when the new order appears in the database so let's double check that let's go to the orders here add a new one which will have ID 16 go back and it's right away there so it subscribes correctly and you can add this one on other screens as well when for example if you have other screens where you want to update when new orders are inserted you can do that as well another subscription that I want to show you is the updating the order when the status changes so listening to update events yeah let's let's get this use effect but first we're going to Define in our API order subscription a new hook similar to this one called use update order subscription but when we subscribe to update order orders events we also need to know the IDE of specific orders that we want to listen to because we don't want to listen to the updates to all wers maybe you do but in this case I want to listen to word updates when we are on the worder page so I want only to subscribe to this order with id16 updates so for that this hook will need a ID number and we can take the use effect that will subscribe to update events on our orders table using this filter ID is equal to the ID that we receive here now in the pay low load instead of refetch uh we can simply invalidate the query as we do previously in the query will be not all the orders or maybe we can invalidate all the orders but probably we are interested in orders and then comma the ID we need to make sure that we look what was the query key for order details yeah the second parameter is simply ID we need query client in here so let's make sure we add it before we use a fact and just like that we can use this use update order subscription inside our user orders ID at the top and let's import it from subscriptions and use the same ID here now let's go ahead uh and I don't know maybe we can try to run it on two devices so what I'm going to do actually is I'm going to simulate the iOS being the admin and the Android here being the user so I'm going to create a actually a new account user create account and here we see the menu let's go ahead and add some items to our card for example this pizza margarita let's go ahead and add maybe pepperoni and I think I'm good with my order let's go ahead and check out and pay attention on the admin side because when we press check out as soon as we save a order it should appear on the admin side automatically so now I press check out and we see ERS 17 a few seconds ago with status new on the user side we see the details of a order I can go from the admin side say okay we've got your order it's cooking and on the uh user side it automatically updates to cooking after some time uh the uh the administrator will come back to this order and say hey it's delivering automatically updated here and finally it's delivered and we see the update here and the order goes to the archive for the administrator perfect so that was our uh real time functionality to automatically to listen to updates and automatically update our UI to notify whenever some events are happening real time you don't have to implement this real-time updates for every feature because for example implementing a listener for when new menu items or products are added I don't think makes sense because menu items or products are being created very very rarely so you don't want to Simply listen to subscriptions and once a month to some users to receive it it's better to use subscriptions for data that changes often and data that users expect to see it in real time and update and I think when people are waiting for their orders they are interested to to see as real time updates to it okay so the next task is going to be uh About Storage so far our products that we have added they all are missing their images and now in this lesson we're going to implement the possibility to upload images whenever the admin will select something we will upload it in the cloud we will link it to our product and whenever we are displaying it in our application we're going to download them uh image and render it there so let's have a look at how we can do that using super base here you'll find the quick start for the storage documentation but it's quite simple all we have to do is go to the storage page in the dashboard so let's go ahead in our dashboard let's find the storage and here we're going to see our buckets we already have these avatars buckets it was created automatically when we set up the initial uh user management template we can leave it there it's not going to be any problem but yeah let's go ahead and Implement our bucket we're going to name it product- images so let's create a new bucket the name is is going to be product- images and you can either have public buckets or you can have private buckets that will only be their files will only be accessible by authenticated users so I'm going to have private buckets let's press save and here is our bucket we can manually actually upload files here we can create folders and we can upload files like images PDFs documents anything and like music and so on can upload any type of files the next step is going to be uploading the image when we do when we create a product here so remember when we select a product what we get back uh in our app admin menu create what we get back from this Peck image is the urri link to the local file on the file system of the device so in the next step we're going to need to read that uh file from the file system transform it to Bas 64 and then send it to uh to to super base so let's first start by installing Expo file system that will help us read files and Bas 64 array buffer I'm going to install them in our application here and inside the create product we're going to actually take this upload image function because I don't think anyone would remember or would write these type of functions from the top of their head so I don't want you to to have this expectation that hey someone actually remembers how to do that no I always have to Google it when it comes to transforming files and reading and Bas 64 and so on but uh yeah this function upload image let's paste it in our create. TSX somewhere in the body of our function we have to import the file system so at the top we going to import rep everything as file system from Expo file system and also what else we will have to import the random uuid is imported from already uh installed Expo crypto and this is helping us create a unique file name because if you leave a file name the same as the file name from the over file from the file system in that case the files might Collide if they have a same name so for that reason I'm overriding the name with a random uu ID the content type I'm going to only um go with image PNG and what's left is having this b64 file representing our image uh we're going to use the super base to import in the storage in this bucket we're going to upload the file and by decoding the Bas 64 decode is imported from B 64 array buffer from here and with this uh command we are uploading the file to Super based storage but uploading like actually is not that complicated like it's more about management and transforming like reading the file transforming to base 64 and so on what we are doing next is uh we are uh returning from this function the puff to the file and we need this puff in order to be to write it into the database to know where to find the image of that product because it it will have a random name so what I'm going to do is we should call this upload image inside the on create let's start with on create in the on create this is the object of a new of a new product so let's do image puff equal a weight upload image and that's it now this one create will become a sync and the image puff will be either string or undefined let's assign the image puff to the image of our product that will be saved in the database and this way we are linking the image uploaded to the storage with the item from the database going to the admin and trying to create a product Styles doesn't exist because I messed up here the file oh let's copy everything here it's going to be easier contrl Z until I find the Styles and after that paste everything in now going to the admin create let's see if we upload this image what's going to happen image question mark invalid inputs for type no that I think that was a warning that we already had it took some time to upload the image as you saw maybe we should add some uh loading indicator but finally it was uploaded if we look in the application the image is not yet displayed if we look here in order to understand what's the error let's go ahead and console log the error here so console log error let's try again to upload an a product error invalid input Syntax for type big int none that's another one and here new row violets Ro level security policy for the table objects we have to to to set up some policies to allow users to upload let's go to the storage product Images Oh in the configuration there are policies so as we can see Avatar has some policies but our product images a newly created bucket does not have yet so let's create a new policy uh let's go with full customization and let's select the operation to maybe select an insert that will allow users to upload and download images but not delete them let's keep it like this for now Target rols will be authenticated let's review save policy now let's try it again and see if that fixed the problem uh the error is null let's look in our product images bucket and we see the newly added image maybe I uh clicked two times on that image so that's why it was uploaded twice and also in the products the image is linked here properly we would expect the image to already show in our application but if I'm going to look at the latest ones they are even white it's not even the default template because it's trying to render an image with this puff this is only part of the puff for the image and because the images are not public we have to first download them from the storage and only then use them in our application to to render on the screen so in the this step we're going to download the images and because we're going to need this functionality to download the image in multiple places in our application if multiple models will have this uh remote images I decided that we create a custom component called remote image that will uh do this downloading of images let's go ahead and Define it in our components new file remote image TSX let's go ahead and copy the code for this remote image and look at it together it will receive the puff from the database and based on this puff what it will do is it will uh download the image from product images bucket you can also have this name of a bucket configurable through properties but I left it hardcoded and after receiving the data it will receive it in binary so that's why we are defining a file reader uh we are starting to read the data and when we finish downloading it we are simply setting the image in state and from the state we are rendering using the react native image so again this is not something that you have to to remember so that's why we can copy paste it from from from this guide uh let's give it a try and see if it actually works so the remote image will receive a puff and a fullback image and we need to render that in our components product list item product list item instead of this image we're going to import the remote image from remote image now let's replace this one with remote image it's not going to have a source because the source will be defined there instead of source is going to be have a puff the puff to the file or the name of the file which we will take from product. image we saw that in our database this is our puff of a image and a foldback will be the default Pizza image string or null is not assignable to that probably remote image can be string or null and just like that we see the images downloaded and uh displayed in our application we should do that on the product Details page as well so let's go to the application user menu ID and where we have the image we're going to replace it with remote image we're not going to have a source but we're going to have the puff coming from product. image and the foldback will be default Pizza image so this is on the user side but we change we are on the admin let's do the same on the admin menu ID instead of image let's do remote image so if I go to the product Details page for a product where there is an image we see initially the fallback and after that the image is loaded with the right image so that's how we are storing images in Cloud using super base and yeah after the initial setup it's really easy to to replicate this functionality in different parts of application to upload images and so on you can go ahead and also add some loading indication because it takes a little bit of time for the image to uh to upload maybe you'll you can add like a progress bar to let the user know what's happening and other cool thing about this uh remote images you can also when downloading the image superbase has some automatic way of transforming images of scaling down so this can help you optimize the speed of how fast the images are loaded for example on the initial screen where the they take some time as you can see to do that we can look at that documentation but as I remember that would be in our where we download the image so in the components remote image when we call download here we can send a second option with transform and the transform can have a with 50 by 5050 and we're going to see right away like the scale down version of our images it didn't oh feature not enabled for this t I think maybe that's an additional feature didn't know about that so I'm going to remove that transform but know about that if you need to scale down images you can do that with super base all right so that was the storage lesson for uploading images setting up buckets and downloading them in our application so when thinking about what this application is missing for for it to actually be uh usable by a restaurant definitely I would say that payment processing is a required feature for such an application to to exist and that's what we're going to focus today we're going to focus on integrating stripe payments uh we're going to see how to do that but for that we're going to also look into how to run super base locally how to work with our Edge functions after that in the end we're also going to look into esas and push notifications this is Advanced features but also very important for a lot of mobile applications to be able to not notify the users uh to send a push notification when something happens and for our applications we will send push notifications to admins when there is a new order and push notifications to users when the status of their order has changed so pretty excited about this let's go ahead and uh cover it step by step and finish the the whole application as we have it right now before we go into the actual Advanced features I want to stop first and do some cleaning I want to go to the bug fixes and polishing and here I covered a couple of bugs and fixes that would make the application just a little bit better so uh yeah here is our application and there are a couple of bugs that I want to fix first the first one is images not working inside the cart so if I'm going to go to the user side most of these products they simply do not have a image attached when I created them but the ones below they do have an image but when I add them to the card uh their image is missing here and let's have a look at why this is happening we just forgot to add the remote image here so if I'm going to go to the source components there should be um is it a cart list item I think so because it's this one so if I simply remove it yeah something changes so yeah instead of using uh a normal image we're going to use a remote image and we can see how we have done that inside the product list item so in the product list item we see the remote image that we have built that uh is a custom component that we built in the previous part that simply downloads and renders an image from super base storage so for the puff I'm going to take this one card item product image fullback is the default Pizza Styles image as it was before and resize mode contain so I can remove a first first image and leave only the remote one inside the cart list item and now if I'm going to add a product that actually has an image to our card it's going to be rendered correctly so the first task for us is done then we're going to have images not working in the order item list item so that's after going to the checkout on the order page as well we do not have a remote image so that component is order item list item and again as we have done in our card we should swap the image with a remote image make sure to import it here for the puff we're going to use it as it was here item. products. image fullback default Pizza image yeah that's that's okay so we can go to the user I'm going to check the latest order that was placed a few seconds ago and the image is correctly displayed I'm going to move actually this one at the top uh because it also is related to images and specifically images are not uploading when updating a product so this is on the admin side and if I'm going to go here everything is working perfectly when creating a product but when updating one for example if I'm going to go to this new fresh pizza if I'm going to update it and select a new image choose and then update the image is not going to update it's going to stay like this and why because we simply forgot to call a function when a updating so I'm going to go to the source up admin menu create because in this page we are handling both creating of uh a product and updating it if we look at how we uh handle it on the one create we see that we are actually calling the upload image function while in the own update we forgot to do that so let's do the same upload image that we have done in the on create function let's do the same in the on update we're going to have to make the function a sync and this image puff is going to be used in the next statement where we update so instead of image we're going to use the image puff similar to how we had in the one create and just like that I think we should have proper image uh picker when updating a product so if I'm going to do update it's redirecting back and it loads the image and if I'm going to look here it's the new fresh pizza so we see the image has been uploaded correctly so this one is done as well uh another feature that you might need I mean in a production application you will definitely need here I'm talking about the log out functionalities for users for example admins have kind of way of logging out on this index page but the user will not get on this page he will only right away be redirected to the menu to to the main application so that's why we will need a simple profile page that will have a simple button sign out and yeah that's going to help us sign out from the user account if we need to to do that what I'm going to do is inside our source application user we have here the screens from our bottom tab navigation so we have a orders and menu and if I'm going to create a new file here profile do TSX and export from here a simple profile screen component I don't even need react then what we should see if I'm going to go to the user side is a new page in the bottom tubs here if you want to be fancy and change the title and the icon we can go to the layout here scroll down until we see our tabs and we can add as the last one we can add a tuab screen with a name profile because it should match the name of a file title profile and tab bar icon is there a user tab tab bar icon let's see yes there is one and uh we can navigate there and it shows our title there on the top but yeah make sure to remove a header shown false on the profile because on this page we would like to show the header and now we can go back to our profile screen and instead of I don't know we can leave this one here for the profile but what we are interested in is rendering a simple button import it from react native not from react native elements but from react native with a title sign out and on press we're going to have to actually sign out so if I press on this sign out we see the console worn the last step is to actually go ahead and sign out and we're going to do that using uh super base so we imported super based client from our library we're going to use the off module and their sign out we're going to call sign out and if I'm going to press on the button right away we are navigating to the home screen and from here we can again log in as an admin perfect so the sign out is working I'm not going to spend a lot of time on making it look better you can do that I only wanted to show you how to do it technically with super base and yes we are done with all of these tasks I'm going to let them for you and yeah let me go ahead and do a git add everything get commit the next step is going to see how we can run super base locally and why do we need to do that before going to production this is a very good a recommended way to pull your super base instance locally and after your application is production try to test everything locally before you are sure that what you implemented works and and only after that push it to your Cloud instance on super base that is going to be used by the uh in production by the end users so this is a way to separate environments that development environment that we're going to try to use the local as much as possible and production environment we're going to keep using superbase remote uh with superbase local we will also be able to create Edge functions and more of that we're going to see in the next uh in the next step when we will integ great with stripe so let's go ahead and follow the guide for the super base local here I left some information about the documentation on what you have to do for setting up your system for local development with super base so you can go ahead first in the getting started and here you're going to see how you can install the superbase CLI using npm and you can install it in your application where you can install it globally in my my case I'm going to install it I'm going to use npx to interact with super base so for that reason as you can see here I'm not going to have to install anything uh up front because npx automatically installs the superbase package if it's the first time we are using it another requirement that uh I'm not going to go into uh in in depth uh right now is running super base locally using Docker so in order to run our super base inst we're going to have to install and set up Docker desktop on our system because super base uh has containers and when running it locally we simply run it using Docker and that's why we need a Docker desktop install and configure on our system and if I'm going to look for Docker on my machine it's going to start and it should run behind the scenes for for us to be able to run super base on our machine and yeah that that's it now we're going to start by Lo making sure that we are logged in with our CLI and I'm going to go here in a terminal and as I said because I'm going to always use npx I don't need to install super base globally I'm going to use npx super base and write log in I'm already actually logged in but what you can do is go ahead and grab your access tokens and paste them here and uh you should be good to go now we need to initialize super B in our project so for that we need to run super base in it let's go ahead in our project and every time you see super base command remember that we're going to use npx so npx super base init to initialize our local super base configuration in our project and let's select no for this one and super Bas in it has finished what we see here is a new folder called super base and here is some configuration about our super base uh The Next Step would be to link our local super base instance with our remote one so what we have to run is super base link and provide the project reference copy this command but don't press enter yet because we actually need the project reference to take it we're going to go to our super base dashboard here let's go to Project settings and uh we should find the reference ID under the general settings let's copy it and to our terminal we're going to provide this project reference to link our local project with our remote one we need to enter our database password so I'm lucky that I remember the database password most probably you will forget it but that's not a problem because also from Project settings you can go to database and you can reset your database password through here now at our super base local super base is linked with our remote one the last step is to pull all the changes that we we have created through the dashboard and these changes are for example creating our tables uh storage authentication and so on and to pull all the changes locally in our uh super base folder V to do that all we have to run is npx super base DB pull to pull the changes from our remote super base instance that we created and set up on the superbase dashboard to pull it down in our local super base instance it asks us to update the remote migration history table yes we can do that and we have uh it finished what this created is a new file in the migrations directory that basically is a long SQL script that takes an empty database and brings it to the same state as we have created everything here basically creating all the tables that we need all the uh functions and so on so as you can see it creates tables like word items uh columns wers as you can see the only small thing that is missing from here is a trigger so if I'm going to try to execute this one actually let's let's try to do that uh right now when then we're going to see the problem together so now we can commit our local changes probably we're going to do that in a moment let's first try to start our local super base instance to do that we're going to do npx super base start and if we have our Docker uh running on our system superbase will download and start the containers that it needs to run our back end so we see that it's starting our containers and we see at the end a list of information these are quite important URLs and you can get them anytime by simply running npx super base status and for example one of these URLs that are important is the Studio URL and you can see this is a local host URL but when you open it it's similar to how we solve a super base dashboard but this time it's not running anywhere in Cloud it's running locally on our system inside Docker containers inside these Docker containers food work that as you can see it has a lot of containers a lot of things going on behind the sces but we don't have to care a lot about that because everything is managed by super base and and it's the same way as we are working with a remote one the same way we're working with a local one and it has the tables that we need the order items wers and so on how can we connect to the local one because now if I'm going to refresh the application it's still going to connect with a remote one that has all of these pizzas and menus our local one should not have any data at the moment and uh let's see how we can connect to it uh we're going to do that inside our source lib super base because here is where we create the client the superbase client here there are the superbase URL and the super base key uh what we can do is let's go ahead and create thatv file and put these URLs in the environment so Expo now supports environment variables and the ones that we want to make public in the client side we should start with Expo public if I'm not mistaken and then we can call it super base URL for example and the second one is Expo public super base Anonymous key Anon so yeah I'm going to take the old ones I'm going to put them here in our environment just like that and in our superbase client let's simply take them using process Dov dot we're going to take the name Expo public superbase UR L and for the second one it's going to be process. EnV and it's the second variable now uh it's giving us an error because this super B this environment variable can be either string or undefined and let's add a default value like if it's undefined to be an empty string same here but it's still going to give us an error because we have to restart our development server the server that is running our bundling our react native application so let's stop it start it again now Expo will load as you can see here it will load the environment it has the superbase URL and the super base Unown and if we run it on iOS it's loading it's working and it's going to connect with our remote super base right invalid API key I think we should remove let's try to start them again yeah now I think it's going to work let's try with admin yes perfect it's working but the cool thing is that now from EnV we are we can either change the EnV file we can provide like multiple EnV files like an EnV local or we can simply update of a URLs here so to tell our rec native application to connect with our local superbase API and the URL and the unon that we need we can get them by running npx superbase status and here we're going to see the first one is the API URL so let's take this one and provide it as the super base URL and for the key for the super base unon we're going to use the Unown key here that is also provided for us let's do it like this if I'm going to refresh the application we shouldn't have anything and let me do that by running npx superbase you don't have to do that but I'm going to reset my database because by default we shouldn't have anything in our backend we have to create a new account we have to upload new picture new products and so on because remember previously we were working with the remote one now we are connected with a local one uh we're going to do some changes tests here and only when ready we're going to publish our updates to the remote one so now if I'm going to refresh we should see that yeah there are no menu and I should actually sign out and we will also see that there are no users to navigate and see the database context we can go into the local Studio URL and here in the Local Host you should see that there are no profiles and if you look at the authentication users there are also no users now let's go ahead and create an account for example user at notjust dodev let's create the account and we are correctly logged in the user is created in our authentication users but the problem is is that inside public profiles the user is not actually created and why is that that happens because on our remote database if we look at under our database functions where is a function handle new user and this function is responsible for creating a new user in our profiles table whenever a user is registered in our users database so basically connecting our profiles with users if we look in the Local Host this function is also available here but the function should also have a trigger that tells like when the function should uh be executed if we look under the triggers in the Local Host there is nothing that specifies that function and if we look at the triggers uh in our remote superb.com here we will be able to select a schema from here authentication and there is this trigger on of user created that triggers the handle new new user function after inserting something in the table users so when we pull changes from our uh database this trigger was not replicated because it's not under the public schema it's under this the authentication schema so what we can do is we can simply create this trigger if for you it's as well missing we can simply create it and add it as part of of the initial migration so copy this part from here and let's go to our super base folder under migrations there is the first one first migration here if you scroll down a bit you're going to see the code responsible for creating this handle new user function and what is missing B Be besides having this function is a trigger that will trigger that function and with this code snipet we're creating this trigger and we're saying like after a new record is inserted on the off users go ahead and call the handle new user function that will replicate or copy the data inside the profiles after we have this one here we can call the npx superbase DB reset to go ahead and drop all the tables from our local database and run the migration again basically spinning up them the tables again it's restarting the containers and in a moment we should see that everything will be working yeah we see that the reset has been created this the schema has been migrated we can have a look at the Local Host uh schema here under the triggers if I'm going to refresh now we should see one more we should see this one schema authentication for the table users and the function is handle new user if I'm going to create create a new user in the authentication here let's try that again from our application if I'm going to create the same user no we need to create an account the same user at notjust dodev it's creating the account it's saved in the users as it was doing before but now we can check in the public profiles if it was created as well yes it was created with the same ID and this way it's linked with that locally as well so this was a little thing that was not automatically pulled and we had to manually add it to make sure that locally our application is working the same way as it was working remotely I'm going to commit the code here super base local set up and yes we can move on to the next one before we move on to the next one probably you'd want to also for example sign out of this account create an admin account no I need to create it I need to create it with admin this user by default is not going to be an admin but we can go to our local database under profiles for the new user that we created we can change the group manually to admin here and now if I'm going to refresh the page being signed in with the admin we see the initial homepage where we can go to the admin side and for example create a new product to have at least something in our menu let's select uh an image now 99 did I press it or not yes I actually pressed it twice and we can create a new one pepper Roni 1234 create and here they are will they load the images or is there any issues with images as well image null why is that bucket not found yeah because yeah our bucket with a name what was the name of the bucket that we depend on that was also not not something that was replicated so we would have to do that manually if I look at in superb.com if I'm going to look at the storage we have a bucket called Product images and this bucket should also manually be replicated locally if you need that that's not like the most important thing because if you don't need to test them locally it's it's perfectly fine but yeah how did I call them product images it's a public bucket we can save and I can check if if it's going to work now let's see right now still didn't add probably some bucket policies yeah policies for product images again this is not most important thing I can check the policy here allow authenticated users to read to create and I should do the same here but yeah I'm not going to focus like we don't need that locally the only thing is that yeah we're not going to see images here but whenever we are going to push it to to the remote one images will work because we have set up them there so yeah it's not going to prevent us from doing anything only visually we're not going to see images locally now we're going to get started with integrating stripe as a payment processor in our application when it comes to integrating and processing payments for mobile applications there are two ways we could do that there are in up purchases and there are external payment Gates ways so what is the difference between them and when can we choose one over another because sometimes we don't have a choice we have to follow some strict rules first of all in a purchases these are the purchases that are going directly through App Store and Play Store on uh on Android and they are required whenever you are selling for example some additional features in your application or additional content let's say if you have a normal version of application and a pro version of application under a subscription model in that case you don't have a choice you cannot integrate stripe you have to go through uh through the stores through App Store and play store because they are keeping a very big chunk of the fees their platform fees are around 30% currently quite a steal from from them but we cannot do anything because these are their rules and if we want our application to be present on the Play Store and app store we have have to follow the rules that the the platforms are setting however if our application is selling physical goods for example if you have a e-commerce application a delivery application that uh sells food or any other application where the good is not something related to the application but to actually something physical that the person receives in that case App Store and play store they allow you to integrate with external payment providers such as stripe and the benefit of using an external payment provider like stripe first of all is of course low platform fees less than 5% around 2% transfer fees which is much lower than the pl the 30% that App Store and Google is taking so yeah whenever it's possible I highly encourage you to integrate with uh external payment providers like stripe because it's uh much better in terms of the fees and also there are a lot of benefits there as well like handling and managing all the analytical part or um having like additional features that stripe is bringing to the table such as risk and fraud detection and so on the the good thing is that the app that we're currently building is a delivery application and for this kind of use case we are able to implement stripe so that's what I'm going to teach you how to do today so let's go ahead and start that so here are all the resources that will help you understand better how to do that starting with stripe documentation that explains all the flows that you can integrate and so on they have a re native library that we can open here but there is nothing crazy on this page other than a link to the GitHub so you can open the GitHub of the rec native Library we're going to need that in a moment let's just save like this UR else that we're going to need and the guide that will put everything together is this integration guide that explains how you can integrate with stripe and collect payments from customers another important thing that I want to explain before we jump into the coding part is the whole payment flow how everything works inside stripe when handling customer payments there are two main activities that uh that are happening the first one is create creating a payment intent a payment intent is our server preparing all the information for stripe to collect payments this is simply the intention of a user to uh pay something it doesn't mean that the payment has already been collected it's just hey we are planning to collect this amount and based on this information so this is the top flow here in the graph from our customer that he goes to the payment page or to the checkout page from the client side which is our R native application what we are doing is we will send the word information such as the amount that the user will have to pay to our server then our server should communicate with stripe server to server in a very secure way to create the payment intent then stripe will give back to the server the payment intent server will give it back to the client with this payment intent from our client side we can show the payment sheet we can show this payment sheet that will help us collect payment details and collect actual payments so the second one is not going through our server is going directly with the stripe and this is important like to understand that we actually need some server side code in order to make all the integration possible because creating a payment intent should happen from the server it cannot be done on the client side because when creating a payment intent we are using our secret key and the secret key should never be exposed in the client side so for that reason on for the server side because we are using super base we're going to take advantage of super base Edge functions which are serers side functions running in the cloud from that function we're going to create the uh the payment intent and the rest will be handled in our mobile application so that's uh quickly our plan of attack and before we jump into the code let's go ahead and create a stripe account you can create it for free I already have this demo account for stripe and after creating your account I think you're going to have to to confirm your identity but running it in test mode go ahead and switch this one for test mode uh you should see at the top the label test data and with this test mode we are able to integrate and test our integration in development before we launch it and move it to production mode so after we have created a stripe account let's go ahead and in our environment file let's add these two Secrets environment after the superbase URL let's add two more keys one of them is going to be the stripe publishable key and we're going to make this Expo public we're going to prefix it with Expo public because this key is safe to you be used in client side code so yeah we're going to use it to set up our stripe on the client side to take this key we're going to go to our stripe dashboard and here we're going to see the publishable key let's go ahead and copy it from here and paste it in our environment now for the secret key this is important the secret key does not have Expo public and that means that Expo will not include it in the bundle of our application we're going to use it only on the server side code go ahead to your dashboard and under the secret key go ahead and reveal it and copy it paste your secret key in your environment file and we are good to go and ready for the next step our next step is going to be to create a payment intent so if you remember the previous diagram that I explained we're going to start with this part on the server side and the integration between our server and stripe this uh function is going to be responsible for creating a payment intent by connecting directly with stripe so let's go ahead and cover this one first and uh we're going to do that using Edge functions the documentation for Edge functions can be found here so you can open it up in a new uh window that's why we needed the local superbase development because we will have to set up a function and we can do that locally using the CLI and then we can publish it so let's do that by running this command inside our project and the command is simple npx super base functions new and give the name of a function let's call it payment because it's going to uh help us generate the payment intent and later use it for our payment sheet after running this command if we open superbase functions we should sa a payment sheet function folder with the index. TSX here in order to run our function locally what we can do is execute npx super base functions then serve we can give a specific environment file our n file and we need to do that because later on inside that function we're going to use for example the stripe secret key and the publishable key to connect with with stripe and yeah last step here is give it the name of a function and if I do that our function is executed and is being served here now if you look at the index.ts at the end there you're going to see some code that shows you how we can invoke and test the execution of of this function so if I'm going to uncomment this one out to see some of the code here what I have to do is actually add on the first line after V1 I have to add the function name name and the function name is the payment Das sheet so let's do that payment Das sheet and everything else should be prefilled with what we actually need here instead of a name you can write your name and if I'm going to copy this C command in a new terminal uh remember in this one we are running we're serving our function and in a new one we're going to Simply send a request to that function and if everything is working we should see leave a message invalid working creation worker boot error why is that happening location what's location should we try it without location I don't know what's the the location stands for let's give it a try missing authorization header maybe the problem is also that we didn't comment this back out and yeah after running this one more time I see Hello V and the cool thing is that if if you update this code and simply send a new request it will automatically refresh so the code that is serving our function is actually watching our files and whenever we change it it refreshes so now we see a hello world viim and probably should work with location as well but yeah that's not the main point now we simply sent a request here we saw that our function is executing correctly and is responding with with this hello world text perfect but why do we need this function we need this function to create a payment intent to do that we need to interact with stripe server to server let's go ahead and create the logic of connecting with our stripe account in a separate utils file so inside these functions I'm going to create a new folder called underscore utils to keep it at the top UTS and inside utils let's create a new file here stripe. TS one one thing to know about superbase Edge functions is that they are not executed by no GS runtime they are executing inside Deno runtime and you're going to see the difference of that in our next code so let's copy this code that will help us connect uh with our stripe inside our stripe. TS and as you can see the way we are importing stripe is directly using a URL and this is something very specific to Deno with then we don't have to install something with package.json we can import it through URL and then we'll we'll go ahead and import it and as you can see from this URL the library that we are looking for is an npm Library called stripe with a version 13.10 I took this at 13.10 version by looking at the latest version of stripe on the npm registry so if you go to stripe npm currently for me the latest is 13.10 if there is a newer version of stripe you can take this version and updated here in the URL now uh using the stripe secret key that we are taking from the environment and yeah like using this stripe secret key taken from the environment that is coming from this EnV file we are connecting in a secure way with stripe and later one we will be able to create payment intents but this is the this is the point why we should do this on the server side because we need the secret key and the secret key should never be exposed in the client side perfect let's go ahead back in our payment sheet here and what we're going to do here is first of all let's think about what data we will receive here the data we're not going to receive a name but what we need to know when creating a payment intent is the amount for which we want to create it so we're going to receive the the amount through their request and here I'm not sure if we're going to need anything from here but let's leave it like this for a moment we're going to have to import Stripe from our utilities so import Stripe from util stripe so the stripe client that we just initialized and using that stripe we're going to be able to create a payment intent so let's do that here in our serve function so the payment intent is equal to await stripe. payment intent. create here we need to send some options to the create and one of these options is the amount initially let me simply do 1,99 I'm going to explain it in a moment I'm going to specify the currency as well and the currency is USD and yeah that's it so the amount here is uh actually $10.99 and with tripe we the amount is always represented in the lowest denominator so for USD that's pennies probably for that's cents so that's why it's not 10.99 that's why it's 1,99 and it should always be an integer number we cannot do 10 99.5 because five is a less than a penny and that's not possible to charge that so that's why it should be a number later one I'm going to put in the amount that we receive from request but that's going to be in a moment now for the response that we give back so let's uh create this response we're going to send back the payment intent but we're not going to send everything we're only going to send the client secret and this client secret is something that we will need on the front end to render the payment intent and a good practice is also to send from here the publishable key from environment this Expo publishable key even though this publishable key we are able to import it on the client side it would be better to use it the data that is will be sent from the back end whenever we handle payments in order to make sure that nobody change the client side code so this is also a small security measurement so publishable key we're going to take it using Deno Dov doget and here we need to provide the name so it should be Expo public publishable key now we don't need data anymore we're going to return response stringify response and yeah I think that's everything well for some error handling we can add a try catch to everything that we're doing here like this and inside the catch we can return a new response and we're going to Simply stringify the error but we're going to what for the headers we're going to have the same only the status code will be 400 because there was an error okay perfect now we can go ahead and the function should automatically be restarted when changes happen but I'm going to make sure to restart it manually and we can try to execute it again in the second one using curl and we see here what worker boot Arrow oh because we are sending data name here but it expects amount let me see I'm going to update here a bit for example amount will be 1150 what's going on the request with Deno failed failed to load module no such file or directory if I go to the top I think uh it failed to load this module because it needs needs that dots at the end and oh it's not delay node it's Deno here maybe that was the problem let's send the request one more time maybe restart the the function 400 bed request let me try to console log error here to see what's going on cannot read properties undefined reading create where did we do that in the pay stripe payment intent it should be payment intents sorry for small typos we're going to get there and now finally after sending a request to this payment sheet we get back the payment intent id and the publishable key that should uh should be the same as the one from environment because that's what it returns ends with SS yes so that means that uh now we have a function on the back end that is automatically creating payment intens for us whenever we are sending a request there and I can take this amount and put it directly here and if I'm going to send this request with amount 1150 that should be the data used to create the payment intent we cannot see that yet because the only thing that we know is the secret or the IDE of payment intent but actually if we go to the stripe dashboard if you go under the payments we should see some incomplete payments and these are actually the payment intents and as you can see previous ones are 11 $10.99 but the latest one is150 and that means that we can send uh the amount that we want to charge dynamically through the parameters to our function now that we tested the function locally and made sure that it works correctly what we should do is go ahead and deploy our function on our remote project on our remote super super base instant to do that we're going to run npx super base functions deploy and the name of the function payment it should be functions this will take the code for our function that we created here locally and we'll uh create an edge function on super base and we'll deploy the code there we see deployed function payment and if I'm going to go back to our super base instance but make sure to go to to the actual superb.com not to Local Host and if I'm going to go to the edge functions here we should see a new function payment sheet with more details about it with this step we have finished the small part of handling payments the part from this diagram on our server that calls stripe and creates a payment intent with our data and we return it back to to whoever calls this function fun this function is deployed as an edge function on super base and that enables us to go to the next task in order to get this payment intent information and render a payment sheet on user interface to actually collect the money from the user so this is going going to be our next task and it's going to be stripe and rack native let me first go ahead and do get status create stripe payment intent with superbase Edge function the next step is on our rec native side having a payment intent that is created on the backand side we can go ahead and render the payment collection form or a payment sheet from stripe Expo has uh a good documentation showing how you can set up stripe in an expo project so you can open it up here for more information or we can go ahead and follow the guide that I have prepared so let's start by installing stripe Rec native library in our Expo project I'm going to open a terminal I'm going to run the Expo install and in order to set up our stripe provider we're going to uh use the stripe provider in our layout in the root layout folder and configure it using the publishable key so let's open source ation layout this is our root layout that rubs the whole application so here is where we will import stripe Provider from stripe and we're going to WRA the whole application with the stripe provider it doesn't really matter where you do that as long as the stack is a child of a stripe provider so I can do that probably at the top stripe provider close it here and the stri provider needs only the publishable key as a required variable we're going to take it from the process. env. process. EnV and the publishable key is this one uh it complains that this environment variable can also be undefined so I'm going to do empty string and now everything is working fine with this stri provider has been uh initialized and later in our screens we are able to go ahead and start using it so let's go ahead and create uh a new file in our library that will help us manage the stripe interactions so I'm going to call it stripe. TS and one of the functions that uh we need here is going to be initialize payment sheet this function will receive the amount for which we want to initialize the payment sheet and this is going to be a number and yeah here let's do console. log initializing payment for and here amount let's write now we can uh export this function and when do we want to initialize the payment sheet if I'm going to log in as a user I'm going to add something to my card the moment where I want to initialize the payment sheet is when the user presses check out in some situations you would want to initialize the payment sheet whenever you get on this page but in that situation the user should not be able to change anything in my case on this page the user is still able to change some of the information about his order which changes the total and that's why I'm going to initialize the payment sheet only when we press check out so let's go ahead in the providers card provider and there is this function checkout that simply inserts the order in the table what I'm going to do here is I'm going going to first do a weight initialize payment sheet that was imported from no it shouldn't be here it should be initialized payment sheet from our lib stripe so this function imported from our lib stripe we're going to call it as the first function in the checkout when the user presses on the checkout and we should send here the total amount so the total amount is calculated and saved in variable total here so I can use it as this but remember this total is what we are displaying on the screen and the total in this situation is 9.99 but remember when working with stripe that total I mean the amount that we want to charge should be represented in pennies or cents so for that reason what I'm going to do is from dollars I'm going to multiply by 100 to make it into cents and in order to get rid of anything after the comma because we cannot have floating numbers there we only can have integers I'm going to use MAF dot floor and that will get rid of anything after the dot so we're going to have a integer value of amount of pennies that we want to charge cannot find in it because it's initialized so let's see if this function is being called I'm going to open the terminal running our rec native application I'm going to add something to the card I'm going to press check out and we see initializing payment sheet for $999 yes that's true it's 9.99 which is 999 pennies okay back to our uh stripe to initialize stripe here what do we need there well we need to call our backend function our Edge function and get the information about the payment intent or basically call the server function to create a payment payment intent and then using it we're going to open a model so let's create a new function here for fetching payment sheet parms it's going to be a sync and this function will also need the amount because it will send it to our remote function to our Edge function to fetch the data so remember we have our Edge function that we buil in the previous step and all we have to do is call this function and get back the data to do that we're going to use the super basee client so await super base from super base to call a edge function we're going to use superbase do functions do invoke here we need to the function name and the function name is the name of the folder so it's payment Das shit-shit and the second parameter here we can send uh the body and inside the body we need to specify the amount and the amount is is going to be the parameter as a response we receive a similar response to other superbase functions basically data and error and we can check if there is data we can return it from this function otherwise we're going to I don't know alert something on the screen error fetching payment params and you can return an empty object now let's go ahead and call this fetch parameter function in our when we want to initialize the payment sheet so let's go data equal a wait fetch payment params with the amount now let's console log data if I'm going to go to the user let's try to create a new order if I'm going to press on the checkout we see initializing payment sheet for 1234 and the data back is this object that is coming from our Edge function which means that we successfully created a payment intent on the back end and here is the ID of that payment intent so what we can do here is we will write away the structure the payment intent and the publishable key uh if something happened and there is no payment intent so I'm going to do if no payment intent or if no publishable key I'm going to stop here otherwise I'm going to continue and I'm going to initialize locally the payment sheet we're going to use the init payment sheet that we import from stripe react native and to initialize it we need to send some parameters here one of them is the merchant display name here you can specify the name of your business for example not just dodev then what you need is the payment intent client secret and this is the payment intent that we receive the ID of a payment intent that was created on the back end and the default billing details you can specify the name here Jan do and think that's it with this call we are simply initializing and preparing the payment sheet for it to later be opened so if I'm going to go to the user on the visual side nothing should happen but we can double check if everything is working correctly if we don't have any errors if I don't go on the checkout yeah we don't see any problems any errors which means that most probably it worked correctly lastly after initializing the payment sheet all we have to do is to display to the user so let's have a new function here called open payment this is an sync function and we can also right away export it because we are going to have to call it from our card so yeah what we have to do is we're going to call the a function from stripe called present payment sheet this function was imported from stripe react native and what it does it simply presents the previously initialized payment sheet and if there will be no initialized payment sheet it will throw an error so that's why we are getting the error here and we can do some I don't know small error handling like if error alert error do message and we can also return something from this function to know if everything was successful or not so if there was an error I'm going to return false otherwise I'm going to return true now let's go ahead and call this open payment sheet from our card provider after we initialize the payment sheet so right away we're going to call it let's make sure to import it from our library from stripe library and it will return back the status if if it was successful or not so we can call it paid equal to await and here we can insert the order only if the user paid it so if there was an error don't insert the order in the database so let's have a look I think now is the moment where we will see everything together and now if I'm going to go and create a new order here for $9.99 if I press check out we see that we are required to pay $9 999 here with a credit card because it's in test mode we can use some test cards and one of them is 4242 multiple times and if you try to pay with this card the payment should go through and only then the order is saved into the database and if we go back to our dashboard on stripe under the payments we will be able to see that one and the latest one is actually a payment we that was successfully completed so that means that we have a working setup for collecting payments from the user now you can look at different use cases for example what happens if I don't provide anything and I go back here we're going to see that the payment has been cancelled that is the error that we receive and because in the car provider on the checkout we stopped if the user doesn't pay this order that he is trying to order is not going to be inserted in the database here there are a lot of options how you want to design it maybe you want to save a order but uh have a label that it still uh needs payment in this case I'm going to keep it simple if it's not paid it's not in the database if it's paid we're going to save it so after check out and after we user successfully pay and here in test mode as I said we can use this 42 42 card and we can pay and only then it is saved in the database and the prices are also Dynamic so if I'm going to add a lot of these pizzas we're going to see that that stripe understands automatically that because when creating the payment intent on the back end we are sending the amount that the user should pay here so just like that we have payments integrated in our application working perfectly both on the front end and on our back end and on stripe we can see this information as you can see yes this is the chart on the home screen you should already see some chart start with uh the amount that you made and so on but all of this is still the test data as we are in test mode I'm going to do git add git commit stripe react native so so far we are uh charging customers but we never save information about the customer on stripe and we never kind of Link stripe customers with our database users and because of that every time we are processing the the payments in stripe this is recorded as an anonymous user so if you're going to check the details of one of these payments you're going to see that the customer is unknown or is a guest customer nothing wrong with that like you'd still be able to collect payments the only thing that this will limit you to do is to easily understand who are the customers that are buying again and again from your business and who are the ones that are just joining there is no way to link this uh order with the order of customers from previous time uh and I'm talking about stripe dashboard I'm not talking about our backend and another disadvantage of this one is that users are not able to save their credit card for later and every time they will use our application they will have to manually fill in the information about their payment method so in in this tutorial we're going to learn how to save information about the customers on stripe and how to link that with our database so let's go ahead and see what we have to do first of all we need to add a new field on our user table that will specify a stripe customer ID this way we're going to be able to connect a user in our in our database with a user in stripe so what I'm going to do is I'm still going to run uh first locally so let's go ahead and run npx super base status and make sure your containers are running make sure you have run npx super base start to start your containers and from here I'm going to go to the studio URL to the Local Host Studio URL and from here if I'm going to go to the table views in the profiles at this moment we don't have any fields or if I'm going to look at the definition here is all the fields for our profile what we can do is we can simply change the shape of a table or update the table from our local Studio UI if you are not familiar with SQL this is the easiest way to change the database schema by going here and Visually for example adding a new column the column that we want to add is called stripe customer ID and the type is going to be text so simply add this column at the end click save and now our profiles table they have a new column stripe customer ID currently this is only locally if I'm going to navigate to superb base.com we're not going to see this field under our tables here so here I want to show you how we can do database changes locally and then make sure that we can replicate these changes later either on a different machine or on the remote mode database as we can see here in very mode we still don't have this field what we should do now is generate a new migration file a migration file as I explained previously is an SQL file here in the migration is an SQL file that will take the table from a specific state will apply some SQL commands and we'll move it into a different state so for example what we want to do now is create a new migration that will take our database instance as it is and add a new field to our profile tables again we don't have to create manually these migrations what we can do is use uh a tool that will automatically create a migration for US based on the difference between remote and local database to do that we're going to run npx super base DB and we're going to run the div command and save it in the file called add stripe field so this different diff command we'll look at the local database schema we'll look at the migrations that we currently have and we'll compare the difference and the difference will be saved in a new file and you're going to see right in a moment what that file will be the second file is a file with one single line of code it will when executed it will alter the table profiles and another column called stripe customer ID with type text that's it as simple as is now what you can do is you can push these changes to their remote super Bas instance by using superbase DB push if I'm going to do that now superbase will take the migration from locally and will apply it in the remote database and if we check the super base.com project on the profile that didn't have a column now if I'm going to refresh I suppose it's going to have a column if I scroll to the end yes with stripe customer ID is on the remote superbase instance as well as it is on our local instance perfect now we added both locally and on the remote the extra field that we will need throughout this tutorial we're going to create the stripe customer in our Edge function when we will try to create a payment sheet the way we're going to do that is we know information about the user who is doing this request basically the user who is pressing the check out that user is calling our function and it has an authorization header that identify that user we can check if he is already a stripe customer if yes we're going to use that information for him if no we're going to create a new customer with in stripe and then save it in our database in this stripe customer ID under the profile of that specific user so so here we're going to from our Edge function we're going to have to interact with our superbase database so for that reason in the utils file I'm going to create a new file called superbase dots I left some resources here that will show you how you can interact with super base from Edge functions and this one shows you how you can get information about the authentication context like who is calling our super base client so here is the code that we are interested in in or we can take it from the code that I have prepared so let's copy this starter and let's paste it in our super based TS we are importing the create client uh using the Dano URL import of packages and we are using here a superbase GS library and we are creating a superbase client uh using this environment variables this environment variables will automatically be populated and the additional stuff is we are creating the client using the same authorization token basically the authorization header that we Reed from the user in this way we are impersonating a user now we can simply get the user from the authentication client and because we are using or because we are impersonating him with authorization header we should see information about who is doing this call if there is no user found we're going to see that otherwise we're going to see the information about the user now where should we call this Creator retrieve profile we are going to call this one inside our payment sheet index and here after getting the amount we are going to do const customer equal create or retrieve profile and we're going to have to do a wait here and importing from utils super base TS I don't know why it added withjs V it needs the request information so let's simply send this request Veer and we can also type it with actually request so now when we will try to create a payment intent it will also create a customer Veer so let's go ahead and serve this function npx super base functions serve with the environment file and the name of the function is payment sheet it's the same function that will do a little bit more work so the function is served let's go ahead and I think the easiest way is going to be from our user interface to press check out because whenever we do that we call the backend function and if we're looking at the logs of the backend function we will see here information about what information about the user if I go to the super base here console log user yes the get user form authentication that's what we're console logging and we see that the user is the email is admin at not justd it's exactly the one that I have logged in in my application if I'm going to log in from another account that's going to be reflected here and we have a ID of a user having the IDE of a user what we can do is we can query the profile information and then having the profile information we will know if he's already a stripe customer or not so in our super B here after we get the user we can get the profile so await superbase client Dot from profiles we're going to select all the columns and we're going to only look for the profile where the ID of the profile is equal to the user. ID and we're only going to take one record not a list of them so the data that we we're going to receive is going to be profile and the error we can take it like this now we can add some checks here to make sure that we we actually found the profile so we can check if there is an error or if there is no profile we can simply throw a new error profile not found now we can console log the profile to make sure that we get it from the database correctly if I'm going to go and press the check out again and look at the logs of our Edge function we should see the profile information with stripe customer ID null at the moment stripe customer ID is null but if it would be not null so if profile. stripe customer ID is not null then I'm going to Simply return this value I don't want to create multiple customers if he's already created in stripe and linked with our profile so later we're going to stop here but now if profile stripe customer ID is not defined we have to create a stripe customer to create a stripe customer we're going to use the stripe Library stripe. customers. create and here we need to provide some metadata about the customer such as the email is important so we're going to take the user. email and the metadata metad dat and in the metadata you can add basically any information like IDs or things like that we need to make sure to import Stripe from do stripe and I think it should be stripe dots and after creating the stripe customer let's do console log well we need to get it so const customer equal well let's do console log customer and let's see the logs if it actually creates a strip customer so I'm going to press check out what do we see here invalid request error parameter unknown type G did you mean metad dat yes meta data very good error messages gives you hints where you might have error so let's press check out again and we see this is the customer that was created on stripe last step is to save a customer ID from stripe to our database uh because later we don't want to recreate it so yeah that would be our last step we're going to await super base client Dot from the profiles table I want to update the stripe customer ID and I will set the customer. ID that we created on stripe but not for all the row only the row that we are currently working with that is the profile.id and lastly we're going to return the customer. ID because we will need it later when we call this Creator retrieve profile and that's it if I'm going to press check out again a new customer should have been created on stripe it should have this 2014 at the end and also in our database if I'm going to refresh we should have a stripe customer ID here or it's not from profile or profiles yes from profiles that's what happens when you rush let's try again press check out everything good in the database under this user profile we see the stripe customer ID which means that it link them together and the next time I'm going to try to pay you're going to see that it will not create a new one it will use the same one but we are not done yet because in the payment sheet when we create the payment sheet we should let no stripe that this payment sheet is for the customer that we just created another thing this will correctly link the payments to a specific customer so if I'm going to check out right now for example 999 check out and actually pay you see there is no way to save this card yet yet but the customer is registered so if I'm going to go to the stripe dashboard the last payment should have been made from this customer as you can see it already has the email of a customer that created the last payment it's already not a guest User it's an actual customer that we have created and we will be able to track his invoices over time so if he comes back and checks out again like this on the customer page you're going to see all the payments that he have made throughout all the history of your restaurant for example you're going to see how how much he spent in total and so on so this is a much better way to handle payments to connect it with stripe customers in order to keep track of of your users inside stripe dashboard as well but as I was saying this method does not yet allow us to save credit card informations it doesn't allow us because for that we need a specifically generated key for the customer which is called I'm not going to pronounce that but it's a specific key to generate this let's go ahead in our guide and in the step four there is this code that will create this firal key and let's add it here after creating the customer inside our payment sheet function it's created using stripe do Emeral Keys create we're passing there the customer in the customer ID and this key let's go ahead and send it to our payment intent as well but we don't have to send everything we only have to send the secret there secret now uh this information the customer and the the key let's also add it as a response because later we're going to need it on the front end to send it to the payment sheet all right that's everything on our function back end if I'm going to go to our source Library stripe where we fetch payment sheet information besides these two as you saw previously we also will we will return the customer and the Emeral key so let's take them from here and when we initialize the payment sheet what we can do here is we can send the customer ID of customer and the customer if Emeral key secret this one now if I'm going to refresh the page go to the user s try to order something new if I'm going to add to cart and press check out no payment sheet has been initialized you must call a need payment shet let's do console log data to see what data we get back in the react native side add payment check out initializing and nothing received a no parameter if that's where that's somewhere in our payment sheet function it's this one payment intents when creating the payment intent we do not need it maybe we don't need it when creating the payment intent we only need it to return it here to to the to the client side but it didn't say anything about the customer so let me try to leave a customer but only remove this one from creating the payment intent and try again add to card check out yes now it's works but we don't need this key here look at this now we have a checkbox at the at the end save this car for future not just Dev payments so if I'm going to pay with 42 card and check this box if I'm going to pay this everything is going to work perfectly fine the first time but the next time when I'm going to be hungry and go back here if I will want to check out I can pay with one click because stripe has uh saved our payment information we connected with stripe customer and that's why are able to pay with the car that we already saved there and it's very important to understand that this information about credit cards and so on they are never stored on our system stripe is handling everything for the payments saving and storing this because these are the rules when it comes to handling payment informations the only thing that we saved on our system is a link to stripe customer ID in our profile in this way we can know like based on a user in our system what is the idea of the stripe customer and everything else stripe is handling for us the only thing is we need to send this ID when we generate the payment sheet and we will be able to reuse the cards where are the new one as well uh you can look for stripe test cards and there is a lot of cards that you could test uh the 42 42 is one that will always succeed but at the end I don't know somewhere here you will also find for example insufficient funds is this one so if I'm going to use this card with any valid date and I'm going to save a card for later if I'm going to try to pay I'm going to see an error your card has in sufficient funds so I'm not going to be able to to do that I can go back select the existing one process it and stripe says good luck everything is working yeah I think we also need to make sure to redeploy our function because we have done changes to it so I'm going to stop the execution locally and do npx super base functions deploy payment sheet to make sure that the changes that we have done to the function locally are also deployed to our production super base instance and that's everything that we need the next Advanced feature that I want to implement in our application and a feature that so many of you wanted us to cover push notifications we're going to use Expo push notifications to integrate push notifications in our application and we're going to do that specifically around two events when a new order is submitted by a user we want to notify all the admins with a push notifications that hey there is a new order you probably should do something about it and whenever the admin changes the status of an order we want to notify the owner of that order the user that created it that hey the order is already delivered or is cooking or something like that so yeah uh we're going to do that with push notifications but first for these push notifications uh because we are going to uh use Expo push notification service we're going to need something from yes I didn't plan to go in depth into yes because that would take a lot of time and that is a topic for another tutorial but we need at least a project ID so we need to configure y yes in order for our notifications later to to work in a couple of words yes is stands for Expo application services and is a set of tools that allows us to build submit update and these are the main categories of EAS and it's specifically for react native and Expo applications so we can do that all of this in cloud with Expo services and it allows us for example to build our application for iOS even if we're using Windows that is one very specific use case that I remembered about uh in general with yes you can create automated cicd pipelines whenever you push some code changes to your um to your application it will go ahead and submit a bill to Y yes after that is done it will submit the applications to App Store and Play Store and after that maybe sent you an email that he is a new update all of this automated cicd using G we have covered in the full Stack mobile development course so if you're interested you can check that out but in this uh tutorial we are going to cover very very limited part of esas as I said we need it only for one project identifier you can read more uh under V documentations uh I left some resources here where you you can simply start by installing yes globally on your system so let me do that here to maybe update it if it needs update after that we can do y login and you need an expo account and just log in with your Expo credentials and after that we can configure our Y and yeah let's let's wait for a bit so now we can run y build configure and uh it will ask us if we want to configure it under our name and yes let's do that in our account uh which platforms would you like to configure let's configure it for both IOS and Android and we can see that it generated for us automatically the e. Json file this e. Json contains information about uh different steps uh of a build that we can do with es but what we are interested in is in the app. Json file that now has this extra yeah s project ID configuration so that's exactly what we need out of this part of a lesson because NE in The Next Step the notification depend on it so let me go ahead and do git add git commit setup esas build so let's continue with our tasks and we are getting into actually implementing our push notifications let's open the documentation from Expo and here is the push notification service overview there is a small confusing part when it comes to notifications and the role of Expo in managing and sending notifications the confusion is coming from two one service and one library that have almost the same name so I'm talking here about the Expo push notification service on the other hand is the Expo not ifications Library I will start by simply explaining what are they these two uh service and library and what is the responsibility of each of them so I'm going to start with the Expo notifications Library this is a simple library that allows us to get the device token and we use it in our client side application it also helps us send and display local notifications and yeah basically let's think about export notifications is for managing notifications locally I'm talking about push notifications but they are local for example being able to schedule a notifications every day at 12:00 this is a local notification it's still a push notification because it opens in the systems uh UI and this is managed by Expo notifications nothing more to to say about this we need to use it in any case because it helps us get the token that is later used to identify a device and with that token later we can send even remote notifications but when it comes to remote notifications and remote notifications is let's say when I'm liking a post on Instagram the user who created that post will receive a notifications and this is a push a remote push notification because it is generated by an event from a different device from a different user but the notification is displayed on a different user on a different device usually these notifications are going through two service providers one of them is Firebase Cloud messaging this is fcm for Android notifications and on iOS we have apple push notification service APN because we are building an application with rack native we are building the application both for Android and iOS if we would want to implement notification server ourself we would have to keep track of both fcm the Firebase Cloud messaging and the Apple push notifications so it adds a little bit of complexity I would say quite a lot of complexity to manage all of this routing should it be Android or iOS instead of that Expo created this push notification service and it's very poorly explained like this difference on the documentation so I it took me quite a lot of time to understand how everything is linked together and even here like it doesn't say anywhere push notification service but yeah the push notification service stays in front of Firebase Cloud messaging and apple push notification and we simply send a request to the Expo push notification service and it handles all the routing and navigation and sending it to the right device to re reach the end user so it's much easier for us to do that but this time this is not a client Library this is an actual service working somewhere on some servers of uh Expo previously it was paid now as I see in the uh Q Q&A somewhere here is actually free so I'm happy for that and we can use it because it simplifies quite a bit the way we interact with everything so from the documentation let's open this push notification service and here here we can go to the setup and our goal in the setup phase is to make sure that the user gives us permission to send push notification and after that reading the Expo push token this is a token that we will later need to identify the application installed on a specific device and with this token later we are going to send push notification to specific devices so as you can see we need this C build that's why we configured it in the previous step and now we're going to start by installing the dependencies let's go ahead and do that in our project I'm going to install Expo notifications Expo device and Expo constants and we're going to add the minimal uh working example in this documentation everything is done in up. Gs I really don't want to add a lot of code to our app.js because our app.js is actually our layout the entry point and I don't want to add logic about notifications so actually I'm going to have two files specific for our notifications one of them I'm going to create it in our lib uh and this is going to be functions lowlevel functions that will help us interact with the notifications notifications do TS so from this documentation let me actually take inspiration from here here and take only what we need in the library let's try to copy this register for push notifications so let's copy this function register for push notifications inside our notifications dots there is a lot of things missing here but we're going to add it step by step for example platform imported from react native notifications uh we're going to imported everything as notifications from Expo notifications okay the device should be imported from Expo device so import from export device but it should also be everything as device what else constants should be imported from Expo constant No it should be like this and Expo config here can be null so we can do question mark question mark here and what else I think we are good now so what this code is doing is setting all the configuration for example for Android it creates a channel name it defines the importance of our notifications you can specify the vibration pattern and the color to uh light if the phone has a dedicated light for notifications you can do the configurations here now later we are only going to get be able to request permission and interact with notifications if we're running on device so for that reason on an emulator is not going to work we're going to see it in a moment and what are we doing is we are first getting the permission from the user either getting existing one or if it's the first time we are requesting permissions and after getting the permissions we are getting the Expo push token as sync as I said this is the token that we will need later to send push notifications now uh where are we going to register for these push notifications if we look in this example code from the documentation register push notification is happening in a use effect inside our application and the token that is being received is stored in a state variable because I don't want to add clutter to our layout I'm going to create a new provider that will store the state variables that will handle the interactions with notifications will fetch everything and do this logic so in the providers let's create a file called notification provider. TSX here I'm going to start with the notification provider which is going to be a function receiving children so let's children let's type it with the props with props with children from react perfect and we're going to return basically an empty portal with children inside I'm not even sure that it should be a context provider because I don't think we're going to need to expose any data here so I'm going to start with a simple provider that will let's first of all add the use effect with empty dependency array here that will simply do a console Warr notification or provider in it now let's go ahead and Export default notification provider and in our underscore layout from application basically in our root layout let's do this notification provider where maybe below the stripe I don't even know where it should go let's think if it makes sense if it if it will depend on anything like authentication or query maybe so let's add it after the query as notification provider and make sure to close it also before the query just like this perfect now we see provider in it that means that this use effect has been called and now if we look at the example the same things that happen in our application what we want to do is to do them inside our notification provider so the first step was to register for push notification and then to save a token in state right let's do that let's import the missing function register for push notifications we need to import it from notifications it's not exported yeah we need to export it export and when we receive back the token we are setting it in state so for that reason we need a state variable for Expo push token and set Expo push token this is a use state that we can also type with export push token now what we can do is console log p push token and here let's try the Expo push token like this we see some alerts on our device saying that M must use a physical device for push token and that is coming from our notification library because we are checking here if it's not device when we are alerting must use physical device so for that reason I'm going to connect my phone quickly here is a view of my physical device and I can interact with it here you will see uh on directly on the screen if we look in the console initially the push token is undefined but the second time the push token is an object with data that has this exponent push token so I'm going to go into the our library and where we take the token because it's an object I'm going to take directly the dot data from that uh from that call now if I'm going to look the push token is no longer data but the push token is an actual exponent push token so what we can do with this one I think we already can go ahead and try to use a tool but we can send a test notification if you scroll down to the fourth step here where is Expo push notification tool if I'm going to go here you see we have to provide the push token that we can copy from here this is the push token generate specifically for my device and we can say hello there how are you if I'm going to press send right now if I'm going to go back here I hope to receive a notification no I actually don't receive it because there are still quite a couple of things that we have to implement in order to listen for incoming notifications and display them on our system so let's do that right now and make sure that by the end of this we're going to see a notification on our device back in this documentation at the step two where they show a minimal working example let's continue with some of these steps for example I said that I want to to do this in the provider to set the notification Handler so let's copy this code inside our notification provider at the top so we're going to have to also import here everything as notifications from Expo notifications and this just is some additional configuration on how to handle the notification if it should show alert play sound set BGE and so on let's try again oh boy actually it's working if I have my phone closed and if I'm going to send here a notification you're going to see it right away I receive it hello there how are you and I think that uh yeah hello hello Vadim if I'm going to send it now you should see that it automatically gets on my device hello Vadim with this title if I press it's going to open the application in Expo go and by the way a little disclaimer is that this setup is working automatically without us having to set up anything on the Firebase and app store because we are still running in Expo go whenever we will have to build our application and deploy to the stores in that case we will have to create our own uh fcm tokens and Link them with our project but that's a small step I'm going to show you later how you can do it but yeah just wanted to to specify that this is working just because we are still using Expo go let's go ahead in our documentation and see uh what else do we need to to do here well in the use effect after we register for push notifications the guide also shows how we can add listeners for notifications and these are uh important when we want to not only show it in the user interface but whenever received to actually do something with them so I'm going to copy them from here and let's go in our notification provider in the use effect after we register for push notifications I'm going to paste here this ones so as we can see we need two things we need a reference oh actually we need three things the notification notification listener and response listener so if I'm going to add them here we need to import us ref from react and we see a lot of typescript Errors not a big deal it's still going to work but if you want to get rid of them we should type the notification listener reference as notifications do subscriptions notifications. subscription and for the second ref is going to be is it still subscription and our notification State here I don't know know why we said it to false I'm going to delete that and I'm going to type it as notifications do notification and this token What's Happening Here Yeah they say that it can be undefined so that's why I'm going to add here question mark or Expo token or undefined string or UND defined is not assigned to parameter or Expo push token uh this token is of type string why register for push notifications let token yeah it's actually not Expo push but it's string here in the return what we are doing is we're removing the listeners uh for notifications and we should do that only if there exist so we can check notification listener. current if it's true only then remove it and the same for the second one yeah these are additional small steps in order to make our code bulletproof current now we will see that uh whenever we receive a notification we will also have access to the notification data here in the code as well so I'm going to do notification let's do it like this console log it to see it here initially notification is undefined but if I'm going to send a new one send notification because our application is in foreground this is also very important to understand because application is in foreground the notification that we received will not be displayed in the tray it's going to be there but it's not going to show on top what we will actually see is that actually the notification was received and we have in our state all of the data about it we have a body we have a title if we're going to have additional attachments or something like that we're going to have them here so Additionally you can besides uh showing notifications in the tray when you receive this you can also show like a popup or something like that like hey there is a new order so this is quite important to know like that yes we can receive notification using this listener and if application is going to be in background when we do that we will see the the notification what else what else uh from this documentation Let's see we can take this send push notification function and using this function we're going to later Implement sending remote notifications so let's take this one in inside our library lib notifications and add it at the end we can export it and for example yeah this is going to send a push notification using this Expo push token string okay now we can go ahead and do G at git commit basic push notifications so this was our first part of our notifications in the second one we're going to see how we can send notifications to other users like remote notifications when something happens on one end we want to notify someone else and this scenario we when a new order is created by the user we want to notify all the admins and when a user order status is changed by the Admin we want to notify the user the end user so first of all to power this feature we need to save in our database the push notification of a user to know how to notify him so everything is going to start with should we do locally yes let's try to uh to follow the same steps to update it locally generate the migration and then push it to remote so I'm going to start with npx super base status uh I'm going to open the studio URL here and in the table editor under profiles let's go ahead and edit this table after the stripe customer ID let's go ahead and add Expo pushor token this is going to be also text let's add it save and it was added to our local instance of our database to make sure that we uh track this change with migrations what we have to do is run npx superbase DB diff and then a file name for add for example push token now this will check the difference we'll check what we have changed and we'll do we'll create a new migration file under super base migrations and we see it here it alter T table profiles by adding the Expo push token perfect the last step is to take this local migration and uh push it to to to remote to do that we're going to do super base DB push so migration has been applied now we can go to our remote database on superb.com we can check profiles we can refresh and we should double check if it has the Expo push token column yes it has perfect now whenever we get this push token we need to save it in the user database so here is where we are going to open our providers notification provider and when we register for push notification we are setting it in state let's create a separate function save push token this is an as sync function that will receive the new token string so instead of updating the state here we're going to call the save push token with this token and we're going to do all the logic here for example set Expo push token with token new token actually string or undefined besides saving it into State here we will also want to update the token in the database so for that we're going to do superbase Dot from profiles I want to update the newly added Expo push token column I want to set it to the new token and not to all the rows but only to the one where ID is equal to H the user ID so that means that here we're going to need information about the user ID const user equal use off and there we have user. ID user do ID and yes export push token it still doesn't understand because we have to update our types right but we're going to do that in a moment let's just but you know what uh I'm only going to do this if new token is defined if because sometimes it will not be defined and I don't want to to do anything with it so let's see what's going on here cannot read property ID of undefined user from use of is not provided here is where the order of our providers inside our layout is important because our notification provider yes it is part of the off provider so it should have access to that uh let's see for example use off oh it has profile so maybe I should just take profile yeah let me take just the profile not user and here I'm going to do profile. ID now if I check our database we already see that a user has the push token here and other users will be able to send a notification to him because there there is information about his push token we can send it through the Expo push notification service the first step for storing the push notification token in our database is finished now we need to uh actually send the notification to the user device so I'm going to start with whenever the status of a order changes I want to notify a user that is the owner of that order that hey there is the status has changed so this functionality happens in our admin orders ID and here we have the update status function besides updating the order I also want to notify the user so what I want to do is console log here notify and who I want to notify the user that is the owner of this order order. user ID so now if I'm going to go to hide a little bit this view of my client side and I'm going to go with the simulator for a bit my physical device is going to be the client side which actually I'm going to sign in as so here on the left we have a user side application and on the right I have a admin side application so for example if from the user side I'm going to order something check out no payment sheet has been initialized error fetching payment oh I think I forgot to to set up the environment variables on super base remote a little step back from what we are doing right now to our stripe integration we checked and we tested our stripe integration uh locally but after deploying it to production we didn't check if everything is still working now when I was uh checking later we see that there is something wrong and I realize that the environment variables from our project that are used to configure stripe they are uh they are present locally but they are not uh present in the superbase remote so what we have to do is using superbase Secrets set we can set the secret that we need for these two environment variables so I'm going to open a new terminal here and let's do npx super base Secrets set and I'm going to set the first one and the second one as well so npx super base Secrets set and I'm going to set the stripe secret key as well now if I'm going to do npx super base Secrets uh list we should see a list of Secrets uh yes there is the Expo public and the secret key perfect now let's see if this fixed the the issue of our application that is connected with our production super base instance uh and I'm going to try that by trying to check out yes now it's working so I can go ahead and create here here add my card save it for future and pay the fee processed and we see that this is the order with number 44 and we can get back to to the task that we were working with and here I'm talking about the remote push notifications back to our use case on the left here we have our physical device and this is the user side application that created the order and on the simulator on the right we we will work with the admin side and we're going to go to the wers and the order that the user created with number 44 let's check this out let's open our uh debug tools because when we update the status here we want to notify also the user that the status has been updated so I'm simply console logging something and let's try to update the status from the admin side from new to cooking we see that we are trying to notify the user with this ID perfect that's good uh the only thing is that we need to fetch his push token and we can do that here or we can actually keep all the logic inside the lib notifications and here let's have a function export const get user token and here we're going to receive user ID and what we should return is the user token so to get it we're going to get data and F error we're going to look into our database superbase Dot from profiles I want to select all the columns and only look for the one where ID is equal to user ID parameter and I'm going to return data I don't even need the error and also should do do single to return only not an array but one instance I don't think I want to actually export this function instead I want to ex to I I will keep this one internal and I will export a function const notify user about order update it's const I'm going to actually export it this function will be an as sync function it will receive a user ID and probably the order information and what it will do it will first token equal it will first take the token await get user token by sending the user ID now let's simply console log notifying token so let's uh call this notify user about order update from our admin ERS side so here instead of this console log let's call this function and we're going to send here word do user ID and the information about the word itself maybe we don't even need to to send two variables here because the user ID is part of a order so we can only send the order object and from our notification server we're only going to receive a order and here in the get user token we're going to have order dot user uncore ID if you want to type it uh this order you can do that not sure if we have them here yeah uh what we can do here in the notification service is to type this order par arer using that tables and here wers now let's check that one we have a lot of alerts that must use physical device for push notification if you are tired of that you can get rid of them from from this alert now let's open up the terminal and let's move it to something else and we see property notify user about word doesn't exist doesn't exist because we forgot to import it we need to import it from our our lib notifications and we should also do a wait here and call it only if order is defined because if it's not defined we don't want to call it update order notify this ID and then notifying all the information about the user but we only need the token the Expo push token so in the notifications we are get user token we actually want data do Expo push token and data can beefin so we're going to do that safely like this now if I press delivery we are notifying XO push token perfect that's exactly what we want so having this uh push token what I can do is I can call the above method send push notification for example to token now if I'm going to change the notification here on my physical device on the left I should receive a notification if I press that and if I look here we see original title and here is the body if I'm going to change Here original title to your order is coming it should get there in 10 minutes so as you can see I have my phone closed and the admin for example changes the status to delivering and wece a notification your order is coming it should get there in 10 minutes if I'm going to do that again we're going to receive a new one one and it would be good right now to add custom title and bodies to our send push notification function let's do that here by adding a title which is of type string and a body of type string now we're going to replace this hardcoded title and body and when sending the notification here about user the title is going to be and the body is this one and we're going to send them here title and body let's go ahead and console log the order to see if the new status is there let's see if I do it in cooking the order does it have a status delivering the word status is actually the previous one it's not the newest uh word so that's because we are not waiting for the W to update there update word use update order const update result equal await let me see here console log update result update result let's update it again update result undefined why why is that update order from use update order return mutation why is it undefined update yeah it's not going to work like this I think we we can have a on success here or not I can do it like this D structure everything from the order but override the status with a new the new one created and this way I'm still going to receive a new status if I'm going to go to cooking we see order with status cooking perfect now based on this information we can create the title the title will be your order and we can set the order do status and for the body the body is not that important right now to be honest you can create something else like how much time is left or something like that but now if I'm going to move this word to delivering we're going to see your order is delivering if we're going to put it to cooking your order is cooking if we're going to put it to delivered your order is delivered and only the user of this word will receive this information so now we saw how we can interact and send remote push notifications to the users whenever the status of a user uh updates if you're interested in more information about that you can have a look at how you can send this notifications with Expo push API and as you can see the Expo backend stays before the Fire based and APN for iOS and you simply send it to Expo backend and Expo backend will take care of sending it to ver right device uh there are sdks for backend Integrations for example if you want to send a push notification from your back end side let's say when something happens on the back end you want to send a push notification to the user you can use one of these uh sdks there is one for the SDK node which you can use for example in the Deno runtime as well on super base in a edge function and for example send a notify user users about some activity or uh alternatively as we already did but maybe we didn't pay attention to is that we can send a push notification by directly sending a request to an HTTP endpoint exp. host and with information about the push push token title and body the Expo services will know how to notify your user and this is actually what we used from our front end to send a push notification we send a fetch request a get a post request to Expo we send the the body of a message with the push token of the end user and this way we we actually deliver the notification if you are planning to deploy this application there is one extra step that you're going to have to take and this is in the setup if you go to the get credential for development build at the moment we are using Expo go and that's why it's working because Expo go has this fcm and APN tokens uh by default for you when deploying you are going to deploy your application outside expoo environment so you're going to have to uh set up Firebase Cloud messaging to have Android notifications here are uh some documentations how you can do that and to have them on iOS as well you're going to have to uh set it up for iOS here but for that you need an apple developer account I'm going to go ahead and and commit everything and you're going to have access to all the code all right guys so that was it for today uh thank you for being here and uh yeah uh looking forward for more workshops for our [Music] community
Info
Channel: notJust․dev
Views: 76,255
Rating: undefined out of 5
Keywords: React Native, Supabase, Mobile App Development, React Native Tutorial, Supabase Tutorial, Full Stack Development, UI Design, Backend Development, Online Course, Mobile App Tutorial, App Development Course, react native for beginners, react native tutorial, react native tutorial for beginners, react full course, react native complete course, react native free course, react native hero, full course, free react native course, react native crash course, react native project
Id: rIYzLhkG9TA
Channel Id: undefined
Length: 496min 11sec (29771 seconds)
Published: Tue Feb 06 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.