So now I want to create the exit model which appears when we click on the X button. So let's go ahead and add some things. I'm gonna go ahead and add npx-chat-cnui-at-latest-add-dialog. After the dialog we are also going to do npm install sustent. After that we're going to go ahead inside of my repository, find the public folder and find mascot underscore set.
Go ahead and download this asset and then drag and drop it inside of your public folder like that. Perfect. You can close the github repository. Let's go ahead and create a new folder. We're going to call it store.
Inside of store let's create useExitModel.ts Let's go ahead and import create from toStand. Let's write type exit model state is open is a boolean open is a void and close is a void. And now let's go ahead and export const use exit model. Let's add create from sustained. Let's give it the type of ExitModelState and let's extract Set and let's return an immediate object with the default isOpen of false, open of an empty arrow function which we'll call the set and setIsOpen to true and close which will setIsOpen to false.
Like that. And then let's go ahead and create our exit model component. So I'm gonna go ahead inside of my components folder here and I'm gonna create a new folder called models. Inside of it go ahead and create exit-model.tsx Let's go ahead and mark this as use client. And let's export const exit model.
Like this. And now let's import everything we need from the dialog. So from at slash components UI dialog. So we are going to need the dialog itself, the dialog content, the dialog description, and the dialog footer, header, and title. Like that.
Let's also prepare our button component from ./.UIButton or ./.ComponentsUIButton. And I'm also going to add useExitModel from store.useExitModel which we've just created. So we're going to use the toStand to control our model state. Let's prepare an image from nextImage. Let's prepare useRouter from nextNavigation.
And let's prepare useEffect and useState from React. Now let's go ahead and let's define the router here by useRouter. Let's define client and set isClient or just setClient, useState false. Let's actually make this sentence, this is a boolean let's make it isClient and setIsClient like that and let's... This structure is open and close from use exit model.
Now we're going to do a little trick with the use effect here where we are very simply going to set isClient to true on mount like this. And then we're gonna check if this component has not yet been turned into a client component. We are going to return null. So once the use effect fires, It means that it's rendering on the client side. So just because it has useClient does not mean it's not rendered on the server side.
UseClient simply indicates a boundary to the client. It doesn't mean that this is not rendered on the server. So it's just not a server component. But this can cause hydration errors because of the way we are controlling our models. We are controlling it through zustand.
I hope I'm pronouncing it right. You don't have to control your models using SushTend. It is simply a method that I prefer because I can use this hook in any client component and call it from absolutely anywhere. Some people prefer wrapping their components inside of models and using a specific children as a trigger. I prefer it this way.
It's simply more usable for me. But I do have to suffer with this potential hydration error, which I have to fix using this method. And then let's go ahead and return the actual look of our component. So for that I'm going to add a dialog here. Let's give it an open of isOpen which we can extract from the useExit model and onOpenChange to simply call our close method.
And now I want to go ahead and I want to go to our main layout in the app folder right here and just below the toaster go ahead and add an exit model. So do that very simply from components exit model like this. And now I want to go ahead and go inside of the use exit model from our store folder and change the is open to be true by default. I'm gonna add to do, change back to false. The reason I want to change it to true so that you can actually see what you're developing.
So let's go ahead inside of the exit model and let's add the dialogue content. Let's give the dialogue content a class name of Max with MD. There we go. You can now see your dialogue here. Let's add a dialogue header here and let's create a div with an image component.
Let's give this image component a source of slash mascot underscore sad dot SVG. An alt is going to be mascot. And let's go ahead and give it a height of 80 and let's do the same thing for the width. And there we go, now we have our mascot here. Inside of this div let's give this a class name of flex-items-center, full-width, justify-center and margin-bottom of 5.
Outside of this div encapsulating our image, let's add a dialogue title, which will simply say, wait, don't go. And let's fix this by escaping this using an apostrophe like this so instead of an apostrophe we're gonna use the this sign like that and it's the same thing but we don't have an error or you can just write it like this if you don't like this and let's give this dialogue title a class name of text center font bold and text to Excel And then let's go ahead and create a dialogue description here with a U, let's copy this apostrophe, so you're about to leave the lesson, Are you sure? So we are asking the user to confirm their action. Let's give this a class name of TextCenter and TextBase. And let's go outside of the dialog header and let's add a dialog footer component.
Let's give this a class name of MarginBottomOfFour. Let's go ahead and create a div here with a button which will say KeepLearning. And let's just not misspell this button. So we have added an import from the button right here in our components UI button. So this will say keep learning and let's give this a variant of primary.
Let's give it a class name full width and let's give it a size of large. Let's also give it an on click or to call the close method. So if you want to You can collapse all of these so they are more readable. Let's go ahead inside of this div wrapping the button and let's give it a class name of flex-column-gack-y4-width-full. Let's copy and paste this button and let's call the one below that.
Inside of this one let's give it a variant of danger outline. Instead of keep learning the text is going to say end session and on click is going to be an arrow function which will call the close but also router.push back to the learn page Like that. There we go. That is our closed model. Now go back to UseExitModel state, remove the todo comment if you wrote it and bring this back to UseFalse.
And then let's go back inside of our header component, specifically inside of our app folder lesson header. And now let's go ahead and destructure the open from use exit model, which you can import from store use exit model. And we don't have to put use client here, even though we are using a hook, because again, header component is rendered inside of quiz, which by itself is a client component already. So that is also true for the header itself. If you really want to, you can manually add use client, but that only makes sense if you plan on reusing header throughout different components.
But I strictly want to use this header inside of the quiz component. So For me, this is just fine. And let's very simply add an open here and remove this comment. There we go. Let's try it out.
So now when I click on the X button, there we go. We have a model. Wait, don't go. You're about to leave the lesson. Are you sure?
If I click keep learning, it just closes and everything is fine. If I click end session, there we go, I am redirected back to the learn page. Great, great job!