تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Fix Seeder Images0:00

We are going to improve the confidence and understanding of what's happening for the users by adding some flash messaging to our application. I think you're going to like this one. Real quick before we begin. Uh, in the previous lesson where we created the deleteUnusedImage command, I've realized that I've actually wiped the seed images. Remember we had 1, 2, 22 JPEG images for puppies and these are technically not used by any puppies.

Remember we had 1, 2 22 JPEG images for puppies and these are technically not used by any puppies, so I had deleted them. How did I find out? I tried to reseed the database after doing some testing and it broke. So let me show you what I've done real quick. This is the PuppySeeder, and remember we had these images, but these were sitting in the storage folder as well. So what I've done is I have replaced these 22 images in a seed images folder right here.

So what I've done is I have replaced these 22 images in a seed_images folder right here. And so I've changed one line of code in the Seeder right here. Instead of reaching for the storage_path, I use the base_path and the seed_images. This is the only line that has changed. Everything else is the same. And so now when we run the php artisan migrate:fresh --seed, it's successfully going to be able to create the images.

Introduce Toast Messaging1:18

And so now when we run the migrate:fresh --seed, it's successfully going to be able to create the images. So in case you're following along, make sure that you update that line here. All right, with that out of the way, it's time to get toasty. So we are going to do flash messaging through what's called a toast component. And to make our life easy, we are going to use a component from ShayUI or recommended by Shay.

And to make our life easy, we are going to use a component from Shay and UI or recommended by Shay and UI I should say. And this component is called soner. Soner is a really cool and really flexible and easy to implement toast. And if you don't know what a toast is, it's simply a little message that comes somewhere on your screen. And so I could show you more demos here on the chat C and UI side, but why don't we go

Install Sonner Component1:55

And so I could show you more demos here on the chat C and UI side, but why don't we go and install the sonar component and so I can show you directly in our application. All right, so we're going to install it with the chat C and CLI. So in my terminal I can go npx sha cn add sonar, and this is going to install the sonar package for us. So it should generate one new file in our UI components. And there it is, resources/js/components/ui/sonar.

So it should generate one new file in our UI components. And there it is, resources, js component, ui, soner. So here's the file, it's importing the soner component and then having a sort of opinionated, uh, themed version of it for us. All right, so let's now go ahead and try to use these components somewhere in our front end. And typically when you use a toast, you want to place it as low in the document body as you can basically right before the closing body tag.

Add Toaster to Layout2:43

as low in the document body as you can basically right before the closing body tag. So for us, it's going to happen in our PageWrapper component. Let's head over there, PageWrapper. And it looks like we haven't typed our children properly. So let's very quickly, let's copilot solid that for us. Thank you. And so we want our toast notification to go right. This is going to go directly inside the body tag

to go right. This is going to go directly inside the body tag and I want it under this D. So let's add a fragment. And right here is where we are going to have a toaster component that should come from the ui/sunner component that we've just installed. Although instead of the relative pass, I think I want to use here the alias @/components

Although instead of the relative pass, I think I want to use here the alias at /components/ui/sunner. So if we look back at the documentation, you can see that once you've installed the toaster components, this is exactly what we've just done. You can use it by calling the toast function that you import from sunner. So let's do exactly that in the function component. Before the return statement, I will try to call toast

So let's do exactly that in the function component. Before the return statement, I will try to call toast and with a bit of luck, yes, we'll be able to import it. And let's start very easy with hello from the page wrapper. Why not? Okay, so we've installed sunner, we have placed the toaster component in our document body and now we're trying to call the toast function. Let's go check the front end. Okay, so I'm going to refresh the page and let's see what happens.

Okay, so I'm going to refresh the page and let's see what happens. And here it is down here. Hello from PageWrapper. Come on. How easy was this? We literally have done nothing. We've imported the component, we've called toast and the toast showed up. How cool is that? So by default it looks like it's showing at the bottom right of the page, but we can of course completely change this. I'm going to try to have the code

of the page, but we can of course completely change this. I'm going to try to have the code and UI side by side so we can see in real time the changes and how they affect the toast. Okay? So neither the code or the UI look their best in these dimensions, but it's going to help us see what's happening. First thing I wanna show you is every time I save the page it's going to trigger a uh, toast. And if I save the page multiple times, check what happens.

it's going to trigger a uh, toast. And if I save the page multiple times, check what happens. We have this giant stack of toast and they are all pertained until they disappear, which is pretty cool. Okay, so let's say we want to place the toast at the top center instead of the bottom, right? Well lemme scroll down here and let's use the TypeScript autocomplete.

Well lemme scroll down here and let's use the TypeScript autocomplete. Glorious goodness. Instead of reading the docs. And so possibly there is a position, uh, yep, there is a position and the options are bottom, center, left, right? So let's try top center save. And here it is at the top center. Nice. Okay, so this is still the default notification and if I go back to the top here

Okay, so this is still the default notification and if I go back to the top here where we call the toast function, you can see that I can append toast. and have access to specific types of notifications like toast.info. And you can see the little i uh, information icon here. Same thing with warning. We got a nice warning triangle and you get the idea. Now we're going to take it one step further.

We got a nice warning triangle and you get the idea. Now we're going to take it one step further by adding some rich colors. So if I add rich colors here, now our warning will have a yellow color, which is pretty cool. And as you can imagine, if I had an error, we would have a red signal and a success would be green. And let's say you wanted to have a close button as well,

and a success would be green. And let's say you wanted to have a close button as well, you might almost guess that closeButton is a prop. And if I save a few times, let's say three times, we are now going to have three items that we can individually close with the closeButton. Very cool. That alone should get you pretty excited. The functionality and the ease of use of the sonar component is remarkable. So now instead of manually called toast on the page

Wire Laravel Flash Messages6:28

of the sonar component is remarkable. So now instead of manually called toast on the page as a demo, we are gonna do something much, much cooler. We are going to write some flash messages. In other words, when the Laravel app has a message to flash to the session, we are going to capture that on the front end and display it. So say a puppy was updated successfully and we've said to send that information from the backend to the front end, the toast, the sonar component is going

and we've said to send that information from the backend to the front end, the toast, the Sonar component is going to pick that up and display it accordingly. That's going to be super cool and we'll have basically nothing to do but set messages on the responses in the controllers. Okay, so here I am in the PuppyController and I'm going to make a demo in the index page, which is the homepage, the list of puppies. And so I'll add a flash message to the session.

which is the homepage, the list of puppies. And so I'll add a flash message to the session. You can do this with request session. And then here we are going to flash and let's say we want to flash a success message and say "you have arrived". And so now Laravel is going to add this flash message to the session for this response only. And so now our job is to go and capture it instead of our manual fake notification.

And so now our job is to go and capture it instead of our manual fake notification that we've tested out. So let's go delete that fake one in the page-wrapper. I am going to get rid of this successful toast fakery and instead we are going to want to pass the flash information to the front end. So we could pass the flash on this response here, but we really want this toast notification to be a site-wide set and forget implementation.

but we really want this toast notification to be a site-wide set and forget implementation. So in other words, we want it to be accessible on every single route on the front end. And so the best place to put that is in the handleInertiaResponse file where we can make things available to every single route like the Z routes, the User and the few things that we've looked at. All right? I said handleInertiaResponse,

and the few things that we've looked at. All right? I said handle Inertia response, but it's handle Inertia request, uh, that I was talking about. And so you can see that here we have the AuthUser that we've used before all the Ziggy routes. And so why don't we add here a flash property? We can be creative here, but since we have a success message test, let's start by having a success go away copilot, which is going

but since we have a success message test, let's start by having a success go away copilot, which is going to take the request session and try to get the success key. And so remember you can access all of these properties with the usePage hook. So what we've done just now is add a usePage property that is flash success. So let's go and see if we can access it back in my page wrapper components I will make use of the usePage hook.

So let's go and see if we can access it back in my page wrapper components I will make use of the usePage hook. So const something something equals usePage from Inertia react. Yes. And so we wanna pass some types here. We want the shared data, you've seen that before. And then we wanna access the props. And so with a bit of luck, we should be able to access flash here. So let's go and see if we can have a pret tag that will js

to access flash here. So let's go and see if we can have a pret tag that will js that stratify this flash message. And so let's see if we can reach it. Aha, check it out. Success. You have arrived. It's working. Alright, so we nearly there. Can you work out how we going to go about this? Check this out. Instead of using the JSON stringier here, I will check if we have flash.success and if we do we can do our toast call.

I will check if we have flash.success and if we do we can do our toast call and even better toast.success and pass the flash.success. So we need to import the toast from Soner for it to work. And we have more squigglies that are going to tell us that flash is of type unknown and that makes sense. Let me explain. If we go in the types, we can see the shared data props, which is what type we have passed to the usePageProps.

we can see the shared data props, which is what type we have passed to the usePageProps. And right now the unknown comes from this basically catch all uh, for all properties that are not listed. But we do know that we actively have added a flash key that is an object that has for now a success, which is a optional I guess, eh, is it always going to be a string? Let's assume that it's a string. And so now if I complete the interface with that flash that success, we're not going to have a problem anymore.

And so now if I complete the interface with that flash that success, we're not going to have a problem anymore because now flash is known to be an optional string. So with that in place, I think we set up, we are going to listen to the actual session flash message from the Laravel backend and our front end is going to pick it up and display it on screen with the correct color and the correct message. Pretty cool. The JSON string gify placeholder is gone and when I refresh the page, we have arrived.

Pretty cool. The JSON string gify placeholder is gone and when I refresh the page, we have arrived. Very cool. I'm going to remove the close cross. I don't really like it and it's as simple as removing the close button here. Feel free to keep it if you like it. Okay, you ready to have your mind blown? I'm going to create a new Puppy and without changing anything, we should see the confirmation.

and without changing anything, we should see the confirmation that the puppy was successfully created. Let's check it out. And I have arrived a couple of times as I saved the file, but let's go to the bottom of the file. Whoops, I need to log in, withSimon@laracast.com. The reason is that I have seeded the database and been logged out. So let's go to the bottom.

database and been logged out. So let's go to the bottom and I will create ever go-to Simon character with the Braves hoodie, which as the weeks go by is getting further and further down the line. And I want you to pay attention to the top as I save happy created successfully. Remember when we created the StoreController, when we redirect to the homepage with the page one, uh, navigation, uh, pagination option, we also pass a little

when we redirect to the homepage with the page one, uh, navigation, uh, pagination option, we also pass a little with message, which is success, blah blah blah. And so the flash.success has been picked up and the blah blah blah message has been shown on screen. Let's go take a look at it in the PuppyController. If I go to the bottom of the store method there, there it is. Um, the line I'm talking about is this one with success Puppy created successfully.

Um, the line I'm talking about is this one with success puppy credit successfully. So that with is the equivalent of doing request()->session()->flash() and then pass the message. And so basically all the places where we've used that with are working now except we are only handling the success, uh, use case for now, but we can beef it out a little bit. So in the page wrapper, why don't we say that if flash('warning') we do toast('flash warning'), let's not do error.

So in the page wrapper, why don't we say that if flash warning we do toast, flash warning, let's not do error. And I'll tell you why in a second. Let's do info. Info. And so again, TypeScript is not going to be happy because our flash object is supposed to have only one key. So let's go in the types file and we are going to add, well, copilot is going to add warning and info. Thank you. Stop with the error. And so let's go in the PuppyController one more time.

Thank you. Stop with the error. And so let's go in the PuppyController one more time and we are going to change the, uh, flash to be a info saying I gotta get used to use super whisper for this. You look fantastic today. I will save myself a lot of time this way. So refresh the page and it's not working. Ah, I know why it's not working, but I want you to tell me. Yeah, good job. What we haven't done yet is in the uh, handle Inertia

Yeah, good job. What we haven't done yet is in the handleInertiaRequest file, we only capture the flash success, but we need to also add the info and warning there. So in handleInertiaRequest, we go and co-pilot once again is going to do everything for us. Hey, and it hasn't done error. Good job attempt number two, refresh the page and why is it an error message? Because co-pilot probably used toast.

and why is it an error message? Because copilot probably used toast that error instead of toast that info. Yep, here we go. toast that error. So we want toast that info here and third time's the charm. We should be good to go with our, you look fantastic today. Info message in blue, good stuff. So why do I keep saying no to co-pilot when a co-pilot wants to add flash that error? The reason is we already have access to these errors.

Toast Validation Errors14:53

to add flash that error? The reason is we already have access to these errors. You might remember this from the form of validation where we were grabbing errors that name errors, that trait, and that was already accessible from the use page props. So it's already there. We don't need to add this to the handleInertiaRequest file. Uh, but it's a little bit different. It's an object, so we can't just flash it.

Uh, but it's a little bit different. It's an object, so we can't just flash it because it's going to have a problem because it needs one, uh, value and not an array or an object of values. So let's do a quick demo of how we could go about this. So like I mentioned, we are not going to add it to the flash object, but instead it already exists as the form of errors object. So if errors,

but instead it already exists as the form of errors object. So if errors, and like I mentioned, we could not do those, that error errors, that is going to explode our up and we are going to be told, uh, objects are not valid as a react child. And the object in question is the errors objects. So the quick and dirty debugging way could be to JSON.stringify these errors like so, and you can already see it here, it's an empty object.

that ified these errors like so, and you can already see it here, it's an empty object. But if we were to go to the form and try submit the form without any data, not only will have the validation here, but you can see that the errors have been ified up here. So if you wanted to implement that properly, uh, we could, well why don't we let copilot tell us what they would do. Basically it's going to iterate over the object that values and then for each render a toast error with the error.

Basically it's going to iterate over the object that values and then for each render a toast error with the error. So let's check it out. So as I refresh the page, the first good thing about this is because there are no keys in an empty object, we don't have an error with an empty object. And then when I submit an empty form, we should have one toast notification for each error. That is fantastic. Now, I'm not sure that you necessarily need this since you already have the

That is fantastic. Now, I'm not sure that you necessarily need this since you already have the uh, error validations here, but I mean there might be a place where the user might not look at a specific space and the toast might grab their attention a little bit more. So why not use it as well. Before we wrap up, let's clean up by going in the PuppyController and removing this placeholder flash demo message.

by going in the PuppyController and removing this placeholder flash demo message. And so if I refresh the page, we shouldn't have any notification at the top. And so we good to go. And from now on, whenever the backend has something to say to the user through the session flash messages, the front end is gonna pick it up and display it accordingly. Great stuff. See you in the next video.

and display it accordingly. Great stuff. See you in the next video.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟