1 00:00:02,190 --> 00:00:07,590 To add the action item to the header, I'll do something which I did in the navigation section as well, 2 00:00:07,800 --> 00:00:09,480 in the components folder, 3 00:00:09,660 --> 00:00:11,470 I want to add my own header button 4 00:00:11,550 --> 00:00:17,160 and now for this, I'll add a new subfolder in there which I'll name UI and my idea here is simple. 5 00:00:17,580 --> 00:00:23,340 I have the shop folder which holds all the components that I use in my shop, that output some shop related 6 00:00:23,340 --> 00:00:30,090 information. In the UI folder, I want have some general UI building blocks which I of course also use 7 00:00:30,090 --> 00:00:35,580 in this shop application but which are not really focused on outputting shop or product related data 8 00:00:35,610 --> 00:00:42,240 but which are simply there to provide some default styling or layout and it's in this UI folder where 9 00:00:42,270 --> 00:00:51,680 I will add my own header button by going in there and importing React from React and then importing 10 00:00:53,540 --> 00:01:02,330 header button from React navigation header buttons, this package I installed at the beginning of the 11 00:01:02,330 --> 00:01:10,370 module, if you haven't done this, make sure you npm install this package and then also import Ionicons 12 00:01:11,090 --> 00:01:15,760 from @expo/vector-icons. 13 00:01:15,850 --> 00:01:23,640 Now to be super sure that you have that installed, run npm install --save @expo/vector-icons, so 14 00:01:23,640 --> 00:01:26,220 that this package is available in your project. 15 00:01:26,220 --> 00:01:28,070 These are the imports I need here, 16 00:01:28,110 --> 00:01:35,990 now I also want to import my colors from the constants folder and there, the colors.js file and now 17 00:01:35,990 --> 00:01:43,880 in here, I'll add my custom header button component which is a normal React component in the end that 18 00:01:43,880 --> 00:01:51,390 receives props and needs to return some jsx and I will of course export my custom header button here 19 00:01:51,390 --> 00:01:51,830 in the end 20 00:01:52,560 --> 00:01:58,020 and now the jsx that this returned here is the header button I'm importing from React navigation header 21 00:01:58,020 --> 00:02:05,090 buttons but I have to configure it in a certain way, use the header button here from React 22 00:02:05,190 --> 00:02:10,280 navigation header buttons. For one, this should receive all the props we get here, 23 00:02:10,280 --> 00:02:15,310 so we just forward those but in addition, I'll set my icons component here to 24 00:02:15,320 --> 00:02:18,460 Ionicons, so that we always use Ionicons for rendering that 25 00:02:18,470 --> 00:02:24,670 and of course you could use one of the different vector icon sets provided by @expo/vector-icons as well. 26 00:02:24,860 --> 00:02:30,800 I'll set the icon size to 23 which I found to work out really well but of course you can experiment 27 00:02:30,800 --> 00:02:33,140 with different values here as well, 28 00:02:33,140 --> 00:02:40,370 also maybe if you're using a different icon set, try out a different icon size. And for the colour, 29 00:02:40,490 --> 00:02:41,990 well there it depends 30 00:02:41,990 --> 00:02:47,150 because on Android, we have like a red background here, for iOS we haven't, 31 00:02:47,150 --> 00:02:50,680 so we need to set a different color based on the platform we're running on, 32 00:02:50,780 --> 00:02:59,760 so I'll actually import the platform from React Native here and then we can check the platform here 33 00:02:59,870 --> 00:03:01,870 and if the OS version is Android, 34 00:03:01,880 --> 00:03:04,970 then I know I have this solid field background, 35 00:03:05,000 --> 00:03:10,820 therefore the icon should be white. On iOS on the other hand, the background is not filled, it's transparent 36 00:03:11,120 --> 00:03:19,090 and therefore on iOS, I'll actually set my icon color to Colors.primary. 37 00:03:19,150 --> 00:03:26,980 Now we can use that to add an icon here on the products overview screen, there in my navigation options 38 00:03:26,980 --> 00:03:27,490 here, 39 00:03:27,490 --> 00:03:35,800 I want to add my header right section, so an icon on the right of my header and for that here, we need to 40 00:03:35,800 --> 00:03:42,610 import a couple of things, we need to import header buttons and item from the React navigation header 41 00:03:42,610 --> 00:03:44,660 buttons package we installed. 42 00:03:44,800 --> 00:03:53,780 I of course also need to import my own header button from components UI header buttons, so this component 43 00:03:53,780 --> 00:04:03,720 we just worked in and now down there, header right is header buttons as a wrapper to possibly have multiple 44 00:04:04,140 --> 00:04:10,950 items in there but I will only add one item, a self closing element, on header buttons before we continue 45 00:04:10,950 --> 00:04:17,430 with the item, we have to set the header button component equal to the header button, so to our own header 46 00:04:17,430 --> 00:04:23,820 button here. And the item can now be configured, it should receive a title which can be cart, it should 47 00:04:23,820 --> 00:04:24,290 receive an 48 00:04:24,340 --> 00:04:28,840 icon name and I actually want to use a different icon based on the platform we're running on, 49 00:04:28,980 --> 00:04:34,590 so therefore from React Native, I will import platform, that is optional, you could use one and the same 50 00:04:34,590 --> 00:04:39,270 icon for both platforms but I think it also looks good to have different icons. 51 00:04:39,270 --> 00:04:47,820 And then here, I'll check platform OS and if that's Android, then I want to use the md cart icon which 52 00:04:47,820 --> 00:04:54,360 is the Ionicon cart icon for material design and otherwise I'll use the iOS cart icon and again 53 00:04:54,360 --> 00:04:57,140 you can find all available icons in this icons list 54 00:04:57,240 --> 00:05:03,540 I showed you earlier in the course, the expo/vector-icon icons list and last but not least when the item 55 00:05:03,540 --> 00:05:09,000 gets pressed, we probably want to do something and for now, I don't do anything but we'll change this soon. 56 00:05:11,260 --> 00:05:12,850 If we now save this, we should see this 57 00:05:12,880 --> 00:05:13,500 icon here, 58 00:05:13,500 --> 00:05:15,220 here it is, here's our cart, 59 00:05:15,280 --> 00:05:21,250 also on Android and now we just have to make sure that when we tap this, we are taken to our cart 60 00:05:21,340 --> 00:05:27,250 screen. For that of course, we have to add some logic or some output to the cart screen. 61 00:05:27,880 --> 00:05:31,610 So inside of the cart screen, we of course have a normal React component, 62 00:05:31,720 --> 00:05:34,070 so we import React from React, 63 00:05:34,090 --> 00:05:43,420 we also import something from React Native and that something is a view component to wrap our screen 64 00:05:43,540 --> 00:05:48,120 maybe, we'll probably output some text as well. 65 00:05:48,380 --> 00:05:54,780 We'll have a couple of cart items being listed there which we can do with a flat list to have optimisation 66 00:05:54,800 --> 00:06:01,580 built-in, probably want to style some things with a stylesheet and I'll also import the built-in button 67 00:06:01,670 --> 00:06:11,060 component. Now my cart screen here as always is a React component and I'll set up this styles object 68 00:06:11,060 --> 00:06:16,910 here with Stylesheet.create so that we can style this component as well and in the end, we export 69 00:06:17,000 --> 00:06:21,030 our cart screen here as a default. 70 00:06:21,070 --> 00:06:24,930 Now you can of course build this cart screen in whatever way you want, 71 00:06:24,940 --> 00:06:32,640 I will build it such that we have a view and in that view, I want to have two main section. The topmost 72 00:06:32,640 --> 00:06:37,660 section is like the summary where I see the total amount and where I have the order now button. 73 00:06:37,980 --> 00:06:43,050 This will be in one row, so I will have a nested view here where I can position items next to each other 74 00:06:43,590 --> 00:06:46,810 where I have like a text where I say 75 00:06:46,810 --> 00:06:55,240 total and then here dollar sign and then my my total price maybe. We can also nest this, 76 00:06:55,250 --> 00:07:03,620 you can have nested text components if you remember without issues to give this a separate color for example, 77 00:07:03,620 --> 00:07:08,670 so for now I hardcode 19.99 in there but later this will be derived dynamically. 78 00:07:08,840 --> 00:07:10,330 So that's one thing 79 00:07:10,430 --> 00:07:18,610 and in addition in that same row here, I want to have a button with a title of order 80 00:07:18,700 --> 00:07:26,120 now where I can press it to place an order, clear my cart and add this to my orders which we have 81 00:07:26,120 --> 00:07:28,750 yet to manage and output it on the order screen 82 00:07:28,760 --> 00:07:38,200 in the end. Now below this summary section, I want to have a flat list with my separate cart items, so 83 00:07:38,200 --> 00:07:39,960 that we can really see what's in the cart, 84 00:07:39,970 --> 00:07:43,360 which products are in there, how much of each product is in there, 85 00:07:43,360 --> 00:07:47,860 so that's another thing I will output there. For the moment here, 86 00:07:47,860 --> 00:07:52,090 I'll just add a view with a text of cart items as a placeholder 87 00:07:52,090 --> 00:07:57,660 but again, this will be a flat list in the future but let's start with the total here. To get that total, 88 00:07:57,660 --> 00:08:04,780 we can tap into Redux because there we are managing our cart, so we can use use selector from React Redux 89 00:08:04,780 --> 00:08:10,810 as you learned to get data out of our store and here, I have my cart 90 00:08:11,010 --> 00:08:21,360 total amount maybe which I get with the help of use selector from my state.cart, slice.cart here 91 00:08:21,390 --> 00:08:27,030 because in the app.js file in combined reducers, I assigned a key of cart here to my cart reducer. 92 00:08:29,060 --> 00:08:33,160 So here I have .cart and then there, inside of the cart reducer, 93 00:08:33,380 --> 00:08:40,780 I manage my total amount and the total amount field so that's what we need to access here, total amount. 94 00:08:40,800 --> 00:08:45,570 This gives the cart total amount and we can now use that down there 95 00:08:45,730 --> 00:08:49,820 and with that to ensure that this also looks good, it's time for some styling. 96 00:08:49,910 --> 00:08:56,450 So on the topmost view here, I'll add a style of screen maybe because this wraps the entire screen 97 00:08:56,450 --> 00:08:57,680 in the end, 98 00:08:57,680 --> 00:09:03,820 then here on that view, I'll add a style of summary because that holds all the summary items, 99 00:09:03,920 --> 00:09:07,130 then here on this text, I'll add a style of 100 00:09:09,710 --> 00:09:20,790 summary text and then here, I'll add a style of amount, so that we can style this amount text differently. 101 00:09:22,270 --> 00:09:23,930 So for styles I want to set, 102 00:09:23,950 --> 00:09:34,840 let's go down to the stylesheet and add screen, summary, summary text and then also, what did I name it? 103 00:09:35,300 --> 00:09:41,820 amount and of course it's as always totally up to you how you now want to style this. 104 00:09:41,820 --> 00:09:47,400 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 105 00:09:47,400 --> 00:09:54,420 the flat list later but I will start simple and we'll just say that I want have a margin in all directions 106 00:09:54,420 --> 00:10:03,390 actually here of 20, so around everything, so that there is some space around everything. Then here, 107 00:10:03,390 --> 00:10:09,210 summary which is our box with all the items in there with the order now and our text should use 108 00:10:09,210 --> 00:10:12,820 a flex direction of row to position items in one row. 109 00:10:12,870 --> 00:10:19,950 I went to align items in the center to make sure they're centered vertically and on their main axis, 110 00:10:20,040 --> 00:10:28,670 I want to use justify content space between so that items have the free space between them and items 111 00:10:28,670 --> 00:10:35,040 are this text here and this button. Besides that, we can add a little bit of margin here, 112 00:10:35,040 --> 00:10:36,360 maybe also of 20 113 00:10:36,360 --> 00:10:42,540 which is mostly important also to have some spacing between the summary and our flat list, therefore I'll actually 114 00:10:42,540 --> 00:10:49,990 use margin bottom here to only have some margin to the bottom and I want to add a padding of 10 here 115 00:10:49,990 --> 00:10:55,030 because the summary should be kind of in an elevated box 116 00:10:55,030 --> 00:11:05,050 and for this box here, I'll go to my product item component and I'll copy my shadow set up here and the 117 00:11:05,770 --> 00:11:12,030 border radius maybe I have here and the background color, so that I have the same look here in the cart 118 00:11:12,040 --> 00:11:16,020 and that's of course up to you whether you want that or not but I'll copy that in there. 119 00:11:17,420 --> 00:11:27,410 For the summary text, I now want to use a font family of open sans bold to really highlight this total 120 00:11:27,980 --> 00:11:33,290 and a font size of 18 and for the amount text in there, 121 00:11:33,290 --> 00:11:36,880 I'll set the color to colors.accent color. 122 00:11:36,890 --> 00:11:44,160 Now for that important of course, you need to import colors from the constants folder and then I use accent 123 00:11:44,150 --> 00:11:50,710 and not primary to really have this stand out. To see whether that looks the way we want it to look, 124 00:11:50,710 --> 00:11:55,660 we need to make sure that tapping this header button in our product overview screen actually takes 125 00:11:55,660 --> 00:11:59,520 us to the cart screen and for that, two things are required. 126 00:11:59,800 --> 00:12:04,510 For one, we need to navigate here but before we can do that, we need to register the cart screen in our 127 00:12:04,510 --> 00:12:11,890 navigator. So I'll do that first, I'll import my cart screen here from the screens folder unsurprisingly, 128 00:12:11,890 --> 00:12:17,980 from the shop folder and there from cart screen and now that's the third screen I add here to this stack 129 00:12:17,980 --> 00:12:26,350 navigator, cart points at cart screen. With that setup added here, we can go back to the product overview 130 00:12:26,350 --> 00:12:33,220 screen and there, we now need that functional form for the navigation options because nav data then 131 00:12:33,220 --> 00:12:37,670 allows us to tap into the navigation prop and call navigate, 132 00:12:37,990 --> 00:12:41,240 hence we need to wrap this in another object which we return 133 00:12:41,300 --> 00:12:50,610 and then here we can call navData.navigation.navigate and there, I go to cart and this of course 134 00:12:50,700 --> 00:12:54,950 is the identifier I just picked in the shop navigator here, 135 00:12:55,050 --> 00:12:58,530 this one. With that, 136 00:12:58,580 --> 00:13:01,050 let's see, if I click here, 137 00:13:01,050 --> 00:13:01,740 there we are, 138 00:13:01,740 --> 00:13:03,030 this is my total, 139 00:13:03,030 --> 00:13:06,610 I actually think the accent color isn't that great there, 140 00:13:06,780 --> 00:13:13,170 so I'll actually go back to the cart screen and style this to use the primary color as well 141 00:13:15,490 --> 00:13:22,060 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 142 00:13:22,060 --> 00:13:29,400 and the carpet once, that total amount looks good to me. Let's also try this on Android of course 143 00:13:29,400 --> 00:13:35,700 to make sure it works there as well and generally works, I add one more red shirt and therefore here 144 00:13:35,700 --> 00:13:41,730 we also see an issue with the way this is displayed. To fix this, on the cart screen, make sure that 145 00:13:41,760 --> 00:13:48,600 on the price, we always just output two decimal places on amount with to fixed too. Now by the way in 146 00:13:48,600 --> 00:13:51,350 case you're wondering where this was coming from, this long number, 147 00:13:51,540 --> 00:13:57,150 this is no bug or nothing really to React Native, this is normal Javascript behavior when you're working 148 00:13:57,150 --> 00:14:05,080 with floating point numbers and of course to fix should not be called on the style here but on the cart 149 00:14:05,110 --> 00:14:11,440 total amount. So this was a normal behavior, not a bug, this is how Javascript internally kind of stores 150 00:14:11,440 --> 00:14:18,530 floating point numbers you could say but now we make sure that this is output correctly with two decimal 151 00:14:18,530 --> 00:14:29,830 places. Missing thing is the button and here I now actually want to use color, colors accent to have my 152 00:14:30,760 --> 00:14:37,190 accent colored button. So if I now go to my cart here on iOS, this is how the button looks like there, 153 00:14:38,920 --> 00:14:41,500 this is now how it looks like on Android. 154 00:14:41,590 --> 00:14:46,690 We can always press this, of course I want to disable it though if there is nothing in the cart 155 00:14:46,990 --> 00:14:55,090 and for that, we now need to get our cart items as well. So cart items can also be fetched with use selector, 156 00:14:55,090 --> 00:15:01,320 also from the cart slice but there, it's the items prop from the cart reducer we're interested in. 157 00:15:01,320 --> 00:15:09,150 So if I have a look at the cart reducer, there you see we have the items property. 158 00:15:09,310 --> 00:15:11,260 This is an object which I'm retrieving now, 159 00:15:11,270 --> 00:15:18,280 so cart items is an object, not an array, actually an array would be better for me here though and therefore 160 00:15:18,370 --> 00:15:25,750 I'll use the long form for getting this and I will return an array here and not an object. So we can get 161 00:15:25,750 --> 00:15:36,260 our transformed cart items here, for example by creating a new array here inside of this selector 162 00:15:36,260 --> 00:15:43,910 function and then we can add a for/in loop to go through all the keys in state.cart.items, so to 163 00:15:43,910 --> 00:15:47,120 loop through all the key-value pairs in this cart 164 00:15:47,120 --> 00:15:51,200 items object we have in there and I want to add each of them 165 00:15:52,950 --> 00:16:01,030 as an item to the transformed cart items. So there I will push a Javascript object which has a product 166 00:16:01,060 --> 00:16:06,850 ID let's say which is just my key because in the ID cart items object, the product ID is stored as a 167 00:16:06,850 --> 00:16:07,930 key if you remember, 168 00:16:07,930 --> 00:16:14,320 so now I add this to the product ID property in this object I add to the transformed cart items array 169 00:16:15,300 --> 00:16:27,240 and besides that, I'll have my product title which is of course state.cart.items for the given 170 00:16:27,240 --> 00:16:30,550 key.productTitle. 171 00:16:30,650 --> 00:16:37,900 If you have a look at your cart item model, you'll see that there, product title and product price are 172 00:16:37,900 --> 00:16:41,510 the property names that hold the product title and product price, 173 00:16:41,560 --> 00:16:43,570 so that's how we access both, 174 00:16:43,570 --> 00:16:49,790 so I'll do the same here for the product price and thereafter, I also need the quantity which is 175 00:16:49,790 --> 00:16:58,770 state.cart.items for the given key.quantity and of course also the the sum which is state.cart 176 00:16:58,770 --> 00:17:05,640 .items.key.sum, again basically just what we had here in the cart item. 177 00:17:05,640 --> 00:17:10,260 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 178 00:17:10,260 --> 00:17:17,690 cart item with an additional product ID property so that I have this in here and now it's this transformed 179 00:17:17,690 --> 00:17:24,300 cart items array which I return after this for loop, so that this selector in the end returns 180 00:17:24,330 --> 00:17:25,850 an array and not an object, 181 00:17:26,040 --> 00:17:32,760 so cart items is now an array which makes it easier for us to use it in the flat list and it also allows 182 00:17:32,760 --> 00:17:38,730 us to check here on the order now button whether we want to disable it by simply checking the length 183 00:17:39,210 --> 00:17:41,000 of this array 184 00:17:41,010 --> 00:17:42,720 we now have in cart items. 185 00:17:43,170 --> 00:17:49,260 So here on the button, we can set the disable prop which it supports thankfully, this is a built-in component 186 00:17:49,260 --> 00:17:56,790 which simply has a disabled prop and there I can check if cart items length is equal to zero, if it is, 187 00:17:56,790 --> 00:18:01,650 then I know it's empty and then indeed I want to disable the button. So disabled receives true or false, 188 00:18:01,730 --> 00:18:08,020 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 189 00:18:08,020 --> 00:18:16,800 cart screen, this is disabled, if I add a product though and I go there, it's enabled and of course 190 00:18:16,890 --> 00:18:20,540 you could also use a different colour for the order now button if you wanted to. 191 00:18:20,550 --> 00:18:26,580 Now with that, we're one step closer to the finished carts and of course the next goal is to output the 192 00:18:26,580 --> 00:18:27,510 cart items.