To add the action item to the header, I'll do something which I did in the navigation section as well,
in the components folder,
I want to add my own header button
and now for this, I'll add a new subfolder in there which I'll name UI and my idea here is simple.
I have the shop folder which holds all the components that I use in my shop, that output some shop related
information. In the UI folder, I want have some general UI building blocks which I of course also use
in this shop application but which are not really focused on outputting shop or product related data
but which are simply there to provide some default styling or layout and it's in this UI folder where
I will add my own header button by going in there and importing React from React and then importing
header button from React navigation header buttons, this package I installed at the beginning of the
module, if you haven't done this, make sure you npm install this package and then also import Ionicons
from @expo/vector-icons.
Now to be super sure that you have that installed, run npm install --save @expo/vector-icons, so
that this package is available in your project.
These are the imports I need here,
now I also want to import my colors from the constants folder and there, the colors.js file and now
in here, I'll add my custom header button component which is a normal React component in the end that
receives props and needs to return some jsx and I will of course export my custom header button here
in the end
and now the jsx that this returned here is the header button I'm importing from React navigation header
buttons but I have to configure it in a certain way, use the header button here from React
navigation header buttons. For one, this should receive all the props we get here,
so we just forward those but in addition, I'll set my icons component here to
Ionicons, so that we always use Ionicons for rendering that
and of course you could use one of the different vector icon sets provided by @expo/vector-icons as well.
I'll set the icon size to 23 which I found to work out really well but of course you can experiment
with different values here as well,
also maybe if you're using a different icon set, try out a different icon size. And for the colour,
well there it depends
because on Android, we have like a red background here, for iOS we haven't,
so we need to set a different color based on the platform we're running on,
so I'll actually import the platform from React Native here and then we can check the platform here
and if the OS version is Android,
then I know I have this solid field background,
therefore the icon should be white. On iOS on the other hand, the background is not filled, it's transparent
and therefore on iOS, I'll actually set my icon color to Colors.primary.
Now we can use that to add an icon here on the products overview screen, there in my navigation options
here,
I want to add my header right section, so an icon on the right of my header and for that here, we need to
import a couple of things, we need to import header buttons and item from the React navigation header
buttons package we installed.
I of course also need to import my own header button from components UI header buttons, so this component
we just worked in and now down there, header right is header buttons as a wrapper to possibly have multiple
items in there but I will only add one item, a self closing element, on header buttons before we continue
with the item, we have to set the header button component equal to the header button, so to our own header
button here. And the item can now be configured, it should receive a title which can be cart, it should
receive an
icon name and I actually want to use a different icon based on the platform we're running on,
so therefore from React Native, I will import platform, that is optional, you could use one and the same
icon for both platforms but I think it also looks good to have different icons.
And then here, I'll check platform OS and if that's Android, then I want to use the md cart icon which
is the Ionicon cart icon for material design and otherwise I'll use the iOS cart icon and again
you can find all available icons in this icons list
I showed you earlier in the course, the expo/vector-icon icons list and last but not least when the item
gets pressed, we probably want to do something and for now, I don't do anything but we'll change this soon.
If we now save this, we should see this
icon here,
here it is, here's our cart,
also on Android and now we just have to make sure that when we tap this, we are taken to our cart
screen. For that of course, we have to add some logic or some output to the cart screen.
So inside of the cart screen, we of course have a normal React component,
so we import React from React,
we also import something from React Native and that something is a view component to wrap our screen
maybe, we'll probably output some text as well.
We'll have a couple of cart items being listed there which we can do with a flat list to have optimisation
built-in, probably want to style some things with a stylesheet and I'll also import the built-in button
component. Now my cart screen here as always is a React component and I'll set up this styles object
here with Stylesheet.create so that we can style this component as well and in the end, we export
our cart screen here as a default.
Now you can of course build this cart screen in whatever way you want,
I will build it such that we have a view and in that view, I want to have two main section. The topmost
section is like the summary where I see the total amount and where I have the order now button.
This will be in one row, so I will have a nested view here where I can position items next to each other
where I have like a text where I say
total and then here dollar sign and then my my total price maybe. We can also nest this,
you can have nested text components if you remember without issues to give this a separate color for example,
so for now I hardcode 19.99 in there but later this will be derived dynamically.
So that's one thing
and in addition in that same row here, I want to have a button with a title of order
now where I can press it to place an order, clear my cart and add this to my orders which we have
yet to manage and output it on the order screen
in the end. Now below this summary section, I want to have a flat list with my separate cart items, so
that we can really see what's in the cart,
which products are in there, how much of each product is in there,
so that's another thing I will output there. For the moment here,
I'll just add a view with a text of cart items as a placeholder
but again, this will be a flat list in the future but let's start with the total here. To get that total,
we can tap into Redux because there we are managing our cart, so we can use use selector from React Redux
as you learned to get data out of our store and here, I have my cart
total amount maybe which I get with the help of use selector from my state.cart, slice.cart here
because in the app.js file in combined reducers, I assigned a key of cart here to my cart reducer.
So here I have .cart and then there, inside of the cart reducer,
I manage my total amount and the total amount field so that's what we need to access here, total amount.
This gives the cart total amount and we can now use that down there
and with that to ensure that this also looks good, it's time for some styling.
So on the topmost view here, I'll add a style of screen maybe because this wraps the entire screen
in the end,
then here on that view, I'll add a style of summary because that holds all the summary items,
then here on this text, I'll add a style of
summary text and then here, I'll add a style of amount, so that we can style this amount text differently.
So for styles I want to set,
let's go down to the stylesheet and add screen, summary, summary text and then also, what did I name it?
amount and of course it's as always totally up to you how you now want to style this.
Now I'll start with the screen, in the end I want to take the full size of the screen if we need to with
the flat list later but I will start simple and we'll just say that I want have a margin in all directions
actually here of 20, so around everything, so that there is some space around everything. Then here,
summary which is our box with all the items in there with the order now and our text should use
a flex direction of row to position items in one row.
I went to align items in the center to make sure they're centered vertically and on their main axis,
I want to use justify content space between so that items have the free space between them and items
are this text here and this button. Besides that, we can add a little bit of margin here,
maybe also of 20
which is mostly important also to have some spacing between the summary and our flat list, therefore I'll actually
use margin bottom here to only have some margin to the bottom and I want to add a padding of 10 here
because the summary should be kind of in an elevated box
and for this box here, I'll go to my product item component and I'll copy my shadow set up here and the
border radius maybe I have here and the background color, so that I have the same look here in the cart
and that's of course up to you whether you want that or not but I'll copy that in there.
For the summary text, I now want to use a font family of open sans bold to really highlight this total
and a font size of 18 and for the amount text in there,
I'll set the color to colors.accent color.
Now for that important of course, you need to import colors from the constants folder and then I use accent
and not primary to really have this stand out. To see whether that looks the way we want it to look,
we need to make sure that tapping this header button in our product overview screen actually takes
us to the cart screen and for that, two things are required.
For one, we need to navigate here but before we can do that, we need to register the cart screen in our
navigator. So I'll do that first, I'll import my cart screen here from the screens folder unsurprisingly,
from the shop folder and there from cart screen and now that's the third screen I add here to this stack
navigator, cart points at cart screen. With that setup added here, we can go back to the product overview
screen and there, we now need that functional form for the navigation options because nav data then
allows us to tap into the navigation prop and call navigate,
hence we need to wrap this in another object which we return
and then here we can call navData.navigation.navigate and there, I go to cart and this of course
is the identifier I just picked in the shop navigator here,
this one. With that,
let's see, if I click here,
there we are,
this is my total,
I actually think the accent color isn't that great there,
so I'll actually go back to the cart screen and style this to use the primary color as well
but the main thing is we can go there and if I now try to add items to the cart, I added the shirt twice
and the carpet once, that total amount looks good to me. Let's also try this on Android of course
to make sure it works there as well and generally works, I add one more red shirt and therefore here
we also see an issue with the way this is displayed. To fix this, on the cart screen, make sure that
on the price, we always just output two decimal places on amount with to fixed too. Now by the way in
case you're wondering where this was coming from, this long number,
this is no bug or nothing really to React Native, this is normal Javascript behavior when you're working
with floating point numbers and of course to fix should not be called on the style here but on the cart
total amount. So this was a normal behavior, not a bug, this is how Javascript internally kind of stores
floating point numbers you could say but now we make sure that this is output correctly with two decimal
places. Missing thing is the button and here I now actually want to use color, colors accent to have my
accent colored button. So if I now go to my cart here on iOS, this is how the button looks like there,
this is now how it looks like on Android.
We can always press this, of course I want to disable it though if there is nothing in the cart
and for that, we now need to get our cart items as well. So cart items can also be fetched with use selector,
also from the cart slice but there, it's the items prop from the cart reducer we're interested in.
So if I have a look at the cart reducer, there you see we have the items property.
This is an object which I'm retrieving now,
so cart items is an object, not an array, actually an array would be better for me here though and therefore
I'll use the long form for getting this and I will return an array here and not an object. So we can get
our transformed cart items here, for example by creating a new array here inside of this selector
function and then we can add a for/in loop to go through all the keys in state.cart.items, so to
loop through all the key-value pairs in this cart
items object we have in there and I want to add each of them
as an item to the transformed cart items. So there I will push a Javascript object which has a product
ID let's say which is just my key because in the ID cart items object, the product ID is stored as a
key if you remember,
so now I add this to the product ID property in this object I add to the transformed cart items array
and besides that, I'll have my product title which is of course state.cart.items for the given
key.productTitle.
If you have a look at your cart item model, you'll see that there, product title and product price are
the property names that hold the product title and product price,
so that's how we access both,
so I'll do the same here for the product price and thereafter, I also need the quantity which is
state.cart.items for the given key.quantity and of course also the the sum which is state.cart
.items.key.sum, again basically just what we had here in the cart item.
So what I'm doing is so to say I'm creating a new cart item, not with my model though because it's a
cart item with an additional product ID property so that I have this in here and now it's this transformed
cart items array which I return after this for loop, so that this selector in the end returns
an array and not an object,
so cart items is now an array which makes it easier for us to use it in the flat list and it also allows
us to check here on the order now button whether we want to disable it by simply checking the length
of this array
we now have in cart items.
So here on the button, we can set the disable prop which it supports thankfully, this is a built-in component
which simply has a disabled prop and there I can check if cart items length is equal to zero, if it is,
then I know it's empty and then indeed I want to disable the button. So disabled receives true or false,
by default it's false but I'll set it to true if cart items length is 0. And now you see if I go to the
cart screen, this is disabled, if I add a product though and I go there, it's enabled and of course
you could also use a different colour for the order now button if you wanted to.
Now with that, we're one step closer to the finished carts and of course the next goal is to output the
cart items.