1 00:00:02,110 --> 00:00:07,300 So to make sure that we're logged out when token expires, I'll add a new function in our 2 00:00:07,300 --> 00:00:08,150 auth action, 3 00:00:08,160 --> 00:00:13,270 so in the actions folder in the auth.js file, I'll add a new function here where I want to set a 4 00:00:13,270 --> 00:00:20,950 timer that basically expires when the token is expired. So we can call this set logout timer for example 5 00:00:21,220 --> 00:00:21,840 and there, 6 00:00:21,880 --> 00:00:31,410 I expect to get the expiration time and in here, we can use the good old set timeout which React 7 00:00:31,410 --> 00:00:38,630 Native supports in its Javascript version to set a timer that expires after this time and let's say 8 00:00:38,630 --> 00:00:43,280 this is a value in milliseconds, so that's just an assumption I have and we have to make sure that we 9 00:00:43,280 --> 00:00:47,530 pass the data in milliseconds therefore. Thereafter 10 00:00:47,540 --> 00:00:55,480 this function here will execute once the token expired and there, the question is now what do we do there? 11 00:00:56,060 --> 00:00:57,890 Well in the end, I want to dispatch logout here, 12 00:00:57,900 --> 00:00:58,980 right? 13 00:00:58,980 --> 00:01:05,490 So therefore set logout timer should probably not be a normal function but actually here, 14 00:01:06,120 --> 00:01:10,370 I will have a function which takes advantage of Redux Thunk, 15 00:01:10,590 --> 00:01:16,680 so where we have this function in a function where this inner function gets dispatch as an argument 16 00:01:17,400 --> 00:01:20,010 and therefore once this async task finished, 17 00:01:20,010 --> 00:01:27,660 once this timer expired, we can dispatch logout, so we can dispatch the result of this action creator 18 00:01:27,660 --> 00:01:29,510 which is this action in the end, 19 00:01:29,670 --> 00:01:32,890 so that happens when the timer is done. 20 00:01:32,910 --> 00:01:38,670 Now when we do logout, I also want to clear any running timers because maybe we have that automatically 21 00:01:38,670 --> 00:01:45,760 set timer here which we're not setting yet but we'll soon do, then I want to clear that timer when we 22 00:01:45,760 --> 00:01:49,110 manually logout so that I don't have that ongoing timer 23 00:01:49,120 --> 00:01:55,670 even though it's redundant. So we can add a new variable maybe at the top of the file here which I'll 24 00:01:55,670 --> 00:02:02,340 name timer which is uninitialized initially and then here when we set a timer, 25 00:02:02,340 --> 00:02:08,760 I will set the result of set timeout to timer or store the result of that in timer which is a pointer 26 00:02:08,850 --> 00:02:12,860 at this timer and add a new function, 27 00:02:12,860 --> 00:02:21,920 maybe here, clear logout timer which is now a normal function, not a function that gets this dispatch 28 00:02:21,950 --> 00:02:29,510 inner function but a normal function where I simply call clear timeout timer and the timer is that variable 29 00:02:29,510 --> 00:02:30,800 which points at the timer. 30 00:02:30,800 --> 00:02:36,080 I just want to check whether timer exists, if it's not undefined and if it is not undefined, I'll call 31 00:02:36,080 --> 00:02:41,620 this, clear timeout is a built-in function built into Javascript to get rid of that timer. 32 00:02:41,840 --> 00:02:43,290 So with that, we can clear the timer 33 00:02:43,290 --> 00:02:47,770 if we don't need it anymore and I want to get rid of it whenever we logout, 34 00:02:47,810 --> 00:02:56,540 so whenever this happens here, I will call clear logout timer and one other thing I need to do when I 35 00:02:56,540 --> 00:03:00,650 logout is I need to clear my async storage of course. 36 00:03:00,650 --> 00:03:09,760 So here, I can call async storage remove item user data, again using that same identifier I used for storing 37 00:03:09,760 --> 00:03:10,470 the data. 38 00:03:10,540 --> 00:03:12,550 So I used user data down there, 39 00:03:12,550 --> 00:03:18,010 I need to use the same identifier for clearing it. Now remove item returns a promise and we could wait 40 00:03:18,010 --> 00:03:18,680 for this, 41 00:03:18,730 --> 00:03:25,080 in that case we would need to return that inner syntax where we get dispatch and we do our async task, 42 00:03:25,090 --> 00:03:31,600 so we move this code here into that and then here we can 43 00:03:31,670 --> 00:03:33,380 dispatch this action. 44 00:03:33,380 --> 00:03:36,500 We could do all of that if we're interested in the result of remove item 45 00:03:36,500 --> 00:03:41,970 but here I am not interested, I'll just fire this and I don't wait for this promise to complete, 46 00:03:42,140 --> 00:03:48,560 instead I immediately return this new action object and I trust that this will complete. 47 00:03:48,590 --> 00:03:51,440 Now of course you could restructure this but that's how I will do it, 48 00:03:51,440 --> 00:03:57,380 this should remove the data from our local storage. So with that, logout does this, 49 00:03:57,380 --> 00:04:03,450 we have the logout timer function which sets a timer which does logout once this expires, 50 00:04:03,450 --> 00:04:07,920 now we just have to make sure that we dispatch this set logout timer 51 00:04:07,920 --> 00:04:15,510 action creator here, that we use this action creator and I want to use this when we authenticate. So we 52 00:04:15,510 --> 00:04:22,630 have this authenticate action here and there in the end, 53 00:04:22,800 --> 00:04:30,770 I need to dispatch set logout timer as well as this here. So there, I will now actually use this 54 00:04:30,770 --> 00:04:37,280 different syntax where we got this inner function which receives dispatch, so that here I can dispatch 55 00:04:37,760 --> 00:04:42,940 set logout timer so that this here is triggered 56 00:04:45,740 --> 00:04:51,590 and of course this also means that here instead of returning this, we also need to dispatch this, so we 57 00:04:51,590 --> 00:04:59,970 dispatch two actions here which is absolutely fine. So I set my timer and I then dispatch the authenticate 58 00:05:00,390 --> 00:05:02,270 action. 59 00:05:02,290 --> 00:05:08,890 Now of course, the logout timer needs to know how long it should take, the expiration time is required 60 00:05:08,890 --> 00:05:17,110 and I expect to get this, this expiry time just to mix up names, as an argument here in authenticate so 61 00:05:17,110 --> 00:05:20,920 that I can forward this here to my logout timer. 62 00:05:20,920 --> 00:05:27,400 That means that every place where we dispatch the authenticate action or where we use this action creator 63 00:05:27,400 --> 00:05:33,100 I should say, this every place where we do this does not just need to provide the userId and the token 64 00:05:33,280 --> 00:05:35,230 but also the expiry time 65 00:05:35,470 --> 00:05:38,580 and that starts here with sign up. When we sign up, 66 00:05:38,590 --> 00:05:46,800 we have our expiration date here and we dispatch authenticate. Now authenticate also needs the expiry 67 00:05:46,800 --> 00:05:47,670 time. 68 00:05:47,670 --> 00:05:52,440 Now the good thing is here it's very easy to find out when this expires because we have it in the response 69 00:05:52,440 --> 00:05:58,730 data, there we have this expires in field which is of course a string, 70 00:05:58,830 --> 00:06:07,970 so with parseInt, we can convert this to be a number and then this will be in seconds, authenticate and 71 00:06:07,970 --> 00:06:11,480 set logout timer expect values in milliseconds, 72 00:06:11,690 --> 00:06:19,540 so I will multiply this with 1000 and I will also add this in login of course. There, 73 00:06:19,580 --> 00:06:23,890 I will also add that as a third argument here 74 00:06:24,110 --> 00:06:31,490 so that for login when we dispatch this authenticate action, we also forward our expiration time which 75 00:06:31,490 --> 00:06:36,520 we're getting back from Firebase. Now we also have one other place where we need to do that 76 00:06:36,530 --> 00:06:38,660 and that's the startup screen because there 77 00:06:38,660 --> 00:06:45,740 we also dispatch authenticate and here we need to calculate the remaining time because this kicks in 78 00:06:45,950 --> 00:06:47,410 whenever we restart the app, 79 00:06:47,420 --> 00:06:51,080 so here we don't know how long it will take for the token to expire and 80 00:06:51,080 --> 00:06:53,100 we need to calculate this. 81 00:06:53,150 --> 00:07:02,060 So here I can calculate the expiration time by basically taking the expiration date which 82 00:07:02,060 --> 00:07:08,090 is a date object and calling get time on it which gives me its timestamp in milliseconds since the 83 00:07:08,090 --> 00:07:09,070 beginning of time 84 00:07:09,800 --> 00:07:14,940 and from that I have to deduct the current timestamp get time, 85 00:07:15,020 --> 00:07:18,820 so the current timestamp in milliseconds. This will be in the future, 86 00:07:18,830 --> 00:07:19,850 this is now 87 00:07:19,850 --> 00:07:24,810 so the difference should be a positive number because I'm checking that this is in the future here, 88 00:07:24,830 --> 00:07:28,280 so this should be a positive number in milliseconds. 89 00:07:28,310 --> 00:07:35,060 So now the expiration time here can be forwarded to authenticate and with that, we should have auto logout 90 00:07:35,330 --> 00:07:36,110 as well. 91 00:07:37,790 --> 00:07:39,450 Now to validate that this works, 92 00:07:39,470 --> 00:07:46,440 let's go to the auth.js file and actually there, in the set logout timer function, 93 00:07:46,560 --> 00:07:53,350 I'll temporarily divide the expiration time by 1000, which means I'll divide the milliseconds by 1000 94 00:07:53,370 --> 00:07:54,960 which turns them into seconds 95 00:07:54,960 --> 00:07:57,320 and that means we should be instantly logged out now. 96 00:07:59,410 --> 00:08:06,940 If I reload, I am logged out but you will soon notice that there's only theoretically works. If I do login 97 00:08:06,940 --> 00:08:12,830 again, I'm logged in and now since I divided the value by 1000, 98 00:08:12,830 --> 00:08:21,370 I should be logged out after 3.6 seconds but I'm not. I can navigate around but if I reload, 99 00:08:22,390 --> 00:08:30,720 indeed now I'm logged out. So it kind of cleaned up the data but it didn't navigate us back to the auth 100 00:08:30,720 --> 00:08:31,530 screen 101 00:08:31,920 --> 00:08:37,710 and the reason for that is that we never instruct React Native to navigate us back to the auth screen, 102 00:08:37,740 --> 00:08:39,250 so that's the missing piece. 103 00:08:39,270 --> 00:08:45,300 Clearing our Redux store is nice but in reaction to that clearance, we need to make sure we're taken 104 00:08:45,300 --> 00:08:52,090 back to the auth screen. To make sure that this happens, we need one place which is always rendered which 105 00:08:52,090 --> 00:08:59,230 wraps our entire app where we can listen to our Redux store and find out when our token is reset to 106 00:08:59,230 --> 00:09:06,480 null so that if that happens, we can navigate back to the auth screen. Now that would be the app.js file 107 00:09:06,490 --> 00:09:08,100 because that wraps everything 108 00:09:08,110 --> 00:09:14,080 but the problem is in there I set up Redux here. So Redux in my store is only available inside of here, 109 00:09:14,080 --> 00:09:19,960 so in nested child components and that's already my navigator component to which I have no direct 110 00:09:19,960 --> 00:09:21,000 access. 111 00:09:21,100 --> 00:09:28,700 The solution is to simply wrap this with another component. I'll create that in the navigation folder 112 00:09:29,090 --> 00:09:33,120 because I'll name it navigation container. 113 00:09:33,140 --> 00:09:37,690 Now this is a normal React component, like this 114 00:09:38,820 --> 00:09:46,650 where I don't need anything from React Native but where I just set up my navigation container component 115 00:09:46,650 --> 00:09:52,980 where I receive props and return some jsx in the end and export this as a default navigation container. 116 00:09:54,380 --> 00:10:02,810 Now in there I want to set up my navigation, so I'll import shop navigator from the shop navigator which is 117 00:10:02,810 --> 00:10:06,230 in the same folder and that will be what I return here, 118 00:10:06,410 --> 00:10:15,110 my shop navigator like this. Now I can use my navigation container here in the app.js file, so instead 119 00:10:15,110 --> 00:10:24,190 of importing shop navigator here, I import my navigation container from the navigation folder and the 120 00:10:24,230 --> 00:10:29,980 from the navigation container file and use navigation container here instead of the shop navigator. 121 00:10:29,990 --> 00:10:34,670 Now this is simply a wrapper around the shop navigator but since it's inside of the provider, I now have 122 00:10:34,670 --> 00:10:36,410 access to Redux there. 123 00:10:36,440 --> 00:10:46,150 So in here, we can import use selector from React Redux and use that here to tap into Redux. 124 00:10:46,190 --> 00:10:54,320 So here in the navigation container, I can simply get access to isAuth let's say by using use selector 125 00:10:55,010 --> 00:11:00,410 that takes this function which gives me access to the Redux state and then I can access state.auth.token 126 00:11:00,410 --> 00:11:06,980 to get access to the token in my auth state slice and use the double bang operator to basically 127 00:11:06,980 --> 00:11:12,620 force this to be true or false and if we have no token, this will be false so isAuth will be false in 128 00:11:12,620 --> 00:11:15,460 that case, if we have a token it will be true, 129 00:11:15,500 --> 00:11:23,780 so isAuth is true if we have a token which makes sense I guess. Now we can use effect here to react 130 00:11:23,780 --> 00:11:25,060 to changes in that. 131 00:11:25,160 --> 00:11:29,480 So here in use effect, my dependency array includes isAuth, 132 00:11:29,480 --> 00:11:37,270 so when isAuth changes, this effect function should run and therefore here, I can then check if we're 133 00:11:37,270 --> 00:11:39,630 not authenticated because that's what I'm caring about, 134 00:11:39,670 --> 00:11:45,910 if isAuth is not true, if it is true I don't care but if it is not true, then I want to navigate to 135 00:11:45,910 --> 00:11:49,220 the auth screen and now we have another problem. 136 00:11:49,390 --> 00:11:55,930 The navigator is here and only in components that are rendered with the help of the navigator we have 137 00:11:55,930 --> 00:12:03,220 access to props.navigation.navigate but thankfully, React navigation gives us an escape hatch. We 138 00:12:03,220 --> 00:12:08,770 can use a ref to get access to the navigation functionality with the help of this component when we 139 00:12:08,770 --> 00:12:17,550 use it in our jsx code. We can create such a ref with use ref with the use ref hook and we simply create 140 00:12:17,610 --> 00:12:20,610 our nav ref here by calling use ref like this 141 00:12:21,270 --> 00:12:27,070 and you should be aware of references in React which is basically a way for you to directly access 142 00:12:27,070 --> 00:12:34,890 an element you render in jsx and now we can add the ref property to the shop navigator and assign this 143 00:12:34,910 --> 00:12:37,450 to nav ref or the other way around. 144 00:12:37,470 --> 00:12:43,020 So this establishes a connection between the nav ref constant and this element which in the end is rendered 145 00:12:43,020 --> 00:12:49,610 here and now with this here in the effect, we can call navRef.current, 146 00:12:49,630 --> 00:12:50,830 this is how refs work, 147 00:12:50,830 --> 00:12:59,660 they have a current property dispatch. Dispatch is a method made available by the shop navigator or 148 00:12:59,660 --> 00:13:05,420 by this app container which it is in the end because shop container is nothing else than what ShopNavigator.js 149 00:13:05,420 --> 00:13:11,010 exports which is such an app container component and this component has a dispatch method which 150 00:13:11,010 --> 00:13:15,110 we can use to dispatch a navigation action. For that, 151 00:13:15,110 --> 00:13:24,650 we now need to import something from React navigation and that something is the navigation actions object 152 00:13:24,650 --> 00:13:29,720 here and then here, we call NavigationActions.navigate 153 00:13:29,900 --> 00:13:36,620 and now this allows us to navigate. However not with auth like this but this requires an object as an 154 00:13:36,620 --> 00:13:41,950 argument where you set up the route name and this can now be auth. 155 00:13:41,960 --> 00:13:47,270 So this is how we can now navigate from inside this component even though it's outside of the navigator. 156 00:13:49,080 --> 00:13:56,610 So this goes to auth whenever our isAuth state changes to not authenticated, this by the way also means 157 00:13:56,610 --> 00:14:03,320 that in the shop navigator, in our logout button, we don't need to navigate here because if we trigger 158 00:14:03,340 --> 00:14:08,670 logout, if we dispatch this action, we clear the token in Redux and therefore this should automatically 159 00:14:08,670 --> 00:14:12,390 trigger our navigation thanks to this navigation container 160 00:14:12,660 --> 00:14:18,140 and therefore now if we save that, we should navigate to auth when the token is invalid. 161 00:14:18,140 --> 00:14:25,530 So now if I login again, after 3.6 seconds, we should be logged out and we should see that we 162 00:14:25,530 --> 00:14:26,800 are logged out, 163 00:14:26,850 --> 00:14:28,690 yes that's looking good. 164 00:14:28,890 --> 00:14:30,320 Let's give it another try 165 00:14:30,330 --> 00:14:30,780 here, 166 00:14:36,990 --> 00:14:37,520 yes, 167 00:14:37,820 --> 00:14:45,490 going back and let's also try manual logging out. So if I go to login, open this, click logout, 168 00:14:45,530 --> 00:14:47,340 this also still works. 169 00:14:47,410 --> 00:14:50,900 So with that, we got the auto logout functionality built-in, 170 00:14:50,950 --> 00:14:57,580 now let's go back to the auth action file and remove this dummy division here because I only did this 171 00:14:57,580 --> 00:15:02,020 for testing, of course I don't want to manually shorten my expiration time, instead 172 00:15:02,020 --> 00:15:08,980 now here we have a functionality that works and that makes sure that no matter if we're signing up or 173 00:15:09,160 --> 00:15:16,210 we're signing in or whatever we're doing, we have a token which we store, which we can use and we're making 174 00:15:16,210 --> 00:15:21,660 sure that we're also logged out automatically if our token expires. 175 00:15:21,700 --> 00:15:24,010 This is the finished application here.