So now that we have a finished screen, I want to implement some models. So let's go ahead and reset our database. So I want you to be on the same challenge that I am. So npm run database seed. This will reset all of our progress here.
And when we refresh the page, we are prompted to choose a course again and then you should only see the first challenge here. So in here I want you to make mistakes. I want you to lose your hearts up to the point where you can no longer get this success or incorrect confirmation. So there we go, I am on two hearts now and I am officially on zero hearts now. So even if I select the correct choice now, there we go, nothing happens.
Because I don't want to indicate to the user whether this is correct or incorrect right they are not supposed to know all that's supposed to happen is that they get an error. So let's go ahead and create our hearts model. So For that I want to go inside of the store, I will copy the useExitModel. So let me copy and paste this like this. And I will call this useHeartsModel.ts.
And now I will replace the name of the exit model in all instances and simply put hearts model. So hearts model state use hearts model and hearts model state in here. So now let's go back inside of our components models. Let's copy the exit model and let's paste it again. And in here I'm gonna go ahead and write what's it gonna be?
Heartsmodel.tsx. Like that. There we go. And let's rename this to hearts model and we are no longer gonna be using store use exit model but instead we're gonna be using use hearts model which means we have to import use hearts model from there as well and we have to replace this to use hearts model. There we go.
So Now I want to go ahead and change this to not use mascot sad. Instead I want to use mascot bad.svg. We don't have that yet in our public folder. So let's prepare our public folder right here. Go inside of my public folder and copy the mascot underscore bad.svg.
So let me go ahead and click on this there we go and simply download this file this is from Kenny Game Assets and now that we have this mascot bad right here Let's go back inside of our hearts model here. So let me just close this. There we go. And in here we're going to change the title to say You Ran Out of Hearts and in the description here we're gonna go ahead and write get pro for unlimited parts or purchase them in the store. And now let's go ahead and let's create two buttons here.
So this one is gonna say Get Unlimited Hearts and this one is going to say No Thanks. So I'm going to change this one to be primary outline and I'm going to change the on click to very simple very simply call close like this and get unlimited hearts is going to be calling the onClick here. The variant is going to stay primary and now we have to create the onClick here. So let's do it above the return here. So constant onClick is going to very simply close the model and do router push to the store like that.
Now that we have our hearts model we can go inside of the app folder inside of our main layout here and simply use it just above the exit model let's add hearts model so make sure you import that from components models hearts model so now we have to find a way to use the hearts model So let's go ahead inside of our quiz component in the lesson. There we go. Let's go all the way to the top here. And right here, I'm going to add the open from use hearts model. There we go.
And I'm going to remap the open to open hearts model. So it's explicit. And I've imported this from store slash use hearts model. And I'm just gonna add it here. There we go.
And now we have to find a way to fire the use hearts model. So let's find where we catch in our on continue here. We catch an error, which currently console errors missing hearts. So now we're gonna replace that and show the hearts model. And now do the same thing in the else where we do reduce hearts if response error is hearts instead of console error we're going to open that and break the method.
So let's try it out now. If I select this and click check there we go you ran out of hearts Get pro for unlimited hearts or purchase them in the store. If I click no thanks I'm simply get this closed but otherwise I can click this and it will redirect me to a 404 page. Perfect So that is one thing finished. So now let's go ahead and do the following.
Let's go inside of the terminal and do npm run database seed again. So this will bring back our hearts and reset any progress we've made. So let me just go ahead and continue here. I will select the Spanish and now what I want to do is I want to answer these items correctly. So let me go ahead and answer all of this correctly all the way to the end.
There we go. Now we have our finished screen. And now when I click continue, I cannot go back to this one because it's in 4.04. So now let's go ahead and let's implement this lesson ID here. So there actually isn't too much work to do here and I'm going to show you why.
So this is what we have to do. We have all the components we need, right? We just have to kind of modify the logic. So let's go inside of the lesson here and in here we're gonna create a new folder Lesson ID and in here we can go ahead and copy this page and paste it in here So I want it to be very similar just like that and now inside of here change the quiz to go to quiz because it's going in outside of this lesson ID folder. And instead of this being lesson page let's call it lesson ID page like that and export default the lesson ID page.
And now in here we're going to create a type props which will accept the parameters and accept an lesson id which is a number or a string if you're working with UUIDs and then in here we can accept those props and we can structure the params and then we can pass those params to the get lesson because remember get lesson can accept an id so we can very simply just pass the params lesson ID just like that and then we don't have to worry about this revalidation and all that stuff. So everything else can stay exactly the same. This is lesson ID, lesson challenges, we have the user progress, we have to add the user. So let me just add a to-do here. Add user subscription so I don't forget that And I will also copy this comment and paste it in the original lesson page here.
So I just don't want to forget that. There we go. And I believe that should pretty much work already. So if I go ahead and click this now, there we go. And you can see how I have my initial completion here.
Great, so there is some things we have to work on here, but you can clearly see how this is a practice. So we are doing a lesson that we already completed, right? So I can now say, if I click here, then I should be redirected to slash lesson, which is this weird semi lesson, which we did in the previous seed scripts, right? We didn't add any challenge options, we just added challenges for the second lesson. So that's why it's appearing like this.
So there's a clear difference between the old one that I can go to, which has all the necessary information. So what we have to do now is we have to resolve this. So I don't want this to appear full if it's a practice. I want to give the user ability to also, you know, fill up this bar as they would usually. But in order to indicate to the user that this is a practice lesson, so they don't get confused, I want to implement something called a practice model.
So let's go ahead and do that. We can do that by going inside of the store again. Let's copy the use hearts model and let's call this use practice model. And inside of here, let's rename our hearts model state with practice model. So we have practice model state, usePracticeModel and practice model state here.
Everything else can stay the same. I added a typo here. Great! And now go inside of components models and you can copy the hearts model here, paste it here and rename it to practicemodel.tsx Let's rename this new practice model. Just make sure you are inside of the practice model, right?
Don't accidentally rename your correct component. So this should be practice model. Like that. And the imports should use the practice model as well. Which means the import here is use practice model which means that in here we use the practice model.
Great! So now let's go ahead and do the following. So in here we're not gonna have any on click so we can remove that. This will stay the same. Instead of mascot bad we're going to use heart.svg.
Let's change this height and width to be 100 and change this alt to be heart. And this is not going to say you ran out of hearts, instead it's going to say practice lesson. And the description is going to say use practice lessons to regain hearts and points. You cannot lose hearts or points in practice lessons. So practice is another way that user can regain the points.
And in here we don't need to have two types of buttons. So I will remove the one that's giving us an error. I will change the variant of this one to simply be primary. I will leave everything as it is. And it will simply say, I understand, right?
There is nothing they can pretty much do besides, you know, acknowledge what we have written and we don't need routers. So we can remove that. There we go. Very simple. And now we can go inside of our app folder layout and we can do the same thing so let's import practice model from practice model there we go and add it just below parts model there we go So now we have to revisit our quiz so we can actually fire up that model.
So let's go inside of lesson and in here inside of our quiz component and I want to open that practice model. So let's go ahead and import from react use. Let's import use mount here. So I only want this to happen on mount. Yes, we could have used use effect, but use mount for me from react use is simply simpler because I know it will only behave on mount, right?
And I would rather use an abstraction around useEffect than just use useEffect to be completely honest with you. So in here, what I need is I need initial percentage. So let me go ahead and do this. Let me add use practice model. So make sure you added this import from store use practice model.
And I will just move this here, use practice model. So the same way we added use hearts model and now we have this error so let's just replace this one to open practice model and now in here we're gonna fire use mount which we've added an import for we don't need the dependency array here So this is an abstraction around use effect. And we can just check if initial percentage is 100, that means the user is visiting this and they have already completed it, right? So we can open the practice model. There we go.
So now when I look at this one, it says a practice lesson, use practice lessons to regain hearts and points. You cannot lose hearts. All right, so I have a little typo here. Where is my practice model? There we go.
You cannot lose hearts or points in practice lessons. Perfect. So let's go ahead and just try something out now. So, well, actually let's not reset this entirely. So first thing I wanna resolve is my progress here.
So I don't want the percentage to appear full. So let's do it like this. Let's go inside of our quiz component. And in here somewhere we should have the initial percentage. There we go.
So we are using the initial percentage in here so let's go ahead and do this we're going to not just assign it like this instead we're going to open an arrow function here and we're going to return if initial percentage is 100 that means this is a practice lesson. So I'm going to pretend that the user is at zero completion because I want to give them an ability to continue learning from zero. Like it's a pretend lesson, right? Otherwise, if it's anything less than 100, that's what we are going to keep as the initial percentage. And there we go.
So now you can see how this looks like. Perfect. And let's see what happens if I go ahead and select an invalid question here. So if I click check, there we go. I have five hearts because this is a practice lesson, which means I cannot lose points here.
Perfect, and if I go back, we won't really keep saving progress on a practice lesson, right? So that is reset. We only keep progress on the currently active lesson. So this is what I want to try now before we wrap this part up. Let's go ahead and do another npm run database seed.
So we can go back to our learn page, right? This is a 404, whoops. So back here. So let's select the Spanish course and let's lose some hearts. So I'm gonna go ahead and select an invalid option here, an invalid option again.
Okay, this is fine. And now I'm going to select the correct one. So there we go. This is correct. This is correct.
Like that. And the last one is correct. So I have finished this now and I have three hearts left. But if I go back to my practice lesson now, there we go, I can use practice lesson to regain hearts. So if I try a wrong one again, I stay at three, perfect.
But if I select the correct one, I should gain, there we go. I just gained a heart back to four. Perfect. And this way I can completely regain my hearts and it should never go above five and it doesn't. Perfect.
And if I click practice again, there we go. We reset the lesson. Perfect. Oh, I remember why I use window location.href. Now I remember.
So in my footer last time, I think we've discussed why do I use window.location.href here? The reason I use it, so is that if you click that while you are on this route, this little practice model never fires. So I just kind of use the hack to re-trigger the use mount. Yeah, You know, I like it, but if you think, if you don't like it, you don't have to use it that way. You can use router push safely, but you are gonna lose an appearance of this model in the end of the lesson.
Great, So we handled that. What I want to handle next is the shop page and the subscription page. Right? So I want to do that next so we can finally purchase and exchange our points for hearts and also a subscription using Stripe. And after that we're gonna do the leaderboard and the quests and see what we have left.
Great, great job!