Adding Tailwind UI layout0:00
Now that we've set up the structure of our multi-tenant application, let's make it look pretty. To do that, I like to use Tailwind UI. This is a premium product that costs anywhere from $149 to $249. To me, that price is worth it for the speed and efficiency I get, along with the beautiful designs. So let's take a look at how we would implement that. Let's grab a hero section for our homepage, and I'm going to grab this second one here. So I'm just going to copy the code with this clipboard, go back to phpStorm, and I'm going to take everything I did have and just paste this in.
So I'm just going to copy the code with this clipboard, go back to phpStorm, and I'm going to take everything I did have and just paste this in. And so now if I go to my browser and give it a refresh, you can see everything is working here. Now I'm not going to implement the full page, but I do at least want to get the Login button working, and I want this button to take me to a registration page where we can register a new User along with a new tenant. So let's get the Login button working first. So to do that, we're just going to look for Login. There's two of these buttons.
Extracting navigation component2:00
And the first thing I want to do is extract the navigation from the rest of this page. It's a bunch of HTML, a bunch of markup on one page. So the navigation actually starts here. This is the desktop navigation, and then this is the mobile. So I'm going to go ahead and find my components directory, and let's just create a new component. This is going to be navigation.blade.php. And let's go back and minimize this, minimize this, and I'm just going to grab all of that and replace it with this x-navigation, and paste it in here, save it. And if I refresh my page, everything is still working. So we know that that component, that Laravel component, is still working.
Mobile menu with Alpine2:43
And if I refresh my page, everything is still working. So we know that that component, that Laravel component, is still working. Okay, so let's get this working with Alpine. The first thing I want to do is wrap everything in a div. Okay, and now let's open all this up so we can take a look at it. And the first thing, if we're going to use Alpine, is we need to initialize our x-data. So we're going to say open is false. This is a JavaScript object. And since this is our mobile menu, let's just go ahead and say x-show equals open. So if I refresh my page here, now the menu is not showing, but let me do it one more
And since this is our mobile menu, let's just go ahead and say x-show equals open. So if I refresh my page here, now the menu is not showing, but let me do it one more time and you can see the menu kind of flashes first and then disappears, and we don't want that. So let's figure out how we can fix that. Let's look at alpine.js on github. And we've got this here. Let's take a look at the x-cloak. So we need to add this style to our app. And then we just need to add this x-cloak directive on the div that we want.
So we need to add this style to our app. And then we just need to add this x-cloak directive on the div that we want. So let's go back. If we go to our welcome.blade.php file, this extends this layout, which extends this layout. And then we've got our styles here. Let's just throw this right in here. And if we go back to our navigation here, let's just make this x-cloak. And if we go back and refresh our page, we can now see there is no flash of the mobile menu, but it's still not working. When I click this, it doesn't open anything.
menu, but it's still not working. When I click this, it doesn't open anything. So let's see if we can find this button and make it work. So if we go back to our code, this button is actually up here on, this is my button that I need. So let's go ahead and just say, on click, we are going to set open equal to true. Now if we go back to our app, refresh the page, and take a look, it does work. Now let's get the close button to work. So down here, all the way down here in the mobile menu, we have another button for the close.
So let's implement that, and in the past, or with other frameworks, that could be kind of a challenging thing, but it's actually really simple with Alpine. So if I just say, @click away, and we'll set open to false. So I'm doing this on the mobile menu, so let's go ahead and refresh the page. So when I open the mobile menu, I can click within here, as much as I want, but if I click outside of it, it closes. So that's really nice. We've got the open, we've got the close, almost everything is working. But let's go back to the code, and you can see that they've also given us this really nice transition.
But let's go back to the code, and you can see that they've also given us this really nice transition. But we're not seeing that in our app, we're going to have to implement it. And it looks a little bit scary and confusing, but it's actually really simple, especially when we're using Alpine. So if we go back to Tailwind UI, and we can click this requires JS, and it gives us some information about how to use the different JavaScript frameworks to implement Tailwind UI. And let's find Alpine. And if we go down here, we can see for enter and leave transitions, they've got everything
Building registration page UI7:28
So let's go ahead and work on that one now. So if I go back into Tailwind UI, and let's go ahead and take a look at the sign in and registration components. So we've got this here. And I kind of like this one. So let's go ahead and copy this. And let's paste it back into our app. We have a Register Livewire component. And if we take everything inside this div and paste this in, let's take a look at our site.
And if we take everything inside this div and paste this in, let's take a look at our site. And now we've got this working here. One thing you may notice is this outline all around the page. And I don't really like that. That's just a part of this tall preset that we downloaded. So let's find the register view here. And it's because it's extending this off template that has this here, we don't actually need any of that. So I kind of just want to go into the base template and where it yields a body.
any of that. So I kind of just want to go into the base template and where it yields a body. So let's go to our view here. And instead of off, we'll just say base. And instead of the section being content, we'll say body. And if I go back here and refresh, now it's taking up the full page, which is what I like. Okay, so let's customize this for what we want. Let's find our register. And we don't want this to be signed into your account. We actually want this to be start your free trial.
So let's just grab all that, delete that, make sure everything still looks good, which it does. And now we just need to add the inputs that we really need. So we have an email and a password, but we want a name and a company. So let's just copy this. And we'll add two more here of this email. It's going to be name. Actually this is not name that's or sorry, this is text input. So let's call this name. And then this would be company name.
So let's call this name. And then this would be company name. And take a look at it looks like our padding is a little bit off. So let's figure out how to get that fixed. Looks like this div has an mt-6 class. So let's add that here. And let's add it here, but not on the top one. Okay. And lastly, we don't need this and we need to change this to register. So we've got the rememberMe and forgotYourPassword.
And lastly, we don't need this and we need to change this to register. So we've got the rememberMe and forgotYourPassword. Get rid of that and signIn will be register. And there we go. We now have our registration page. Now we just need to make this thing work. So let's go back to PHPStorm and find our Register component, which is in our Livewire folder and we can see what was already here from the tall preset that we already had. So let's add the things we need. We have a name.
Register user and tenant10:40
So let's add the things we need. We have a name. We need a company name, we have email and password. I don't need a password confirmation. Now before we do the rest of the updating, let's just kind of look at what's going on here. So to update the input, we're going to create a User and then send a email verification, log in the User and redirect to home. Now the one thing we're going to have to do, because again, we're building a multi-tenant application.
Now the one thing we're going to have to do, because again, we're building a multi-tenant application. Let's create a tenant. And all we're going to do is say name is this company name. Okay. And then once we do that, when we create our user, we want to assign the user a tenant_id of tenant_id. One other thing you may remember is we added a role to the users table as well. And this is going to be an admin user because they are registering the account. So they're going to have the ability to add other users and administer the account.
Wiring form with Livewire11:31
And this is going to be an AdminUser because they are registering the account. So they're going to have the ability to add other Users and administer the account. So now it looks like I need to just import this. And now I will update my validation off screen. And everything else here looks good. Now let's model it up in Livewire. Great. So now let's implement this form using Livewire. So let's replace this code with wire:submit.prevent. And we're going to use the name of the method we want to call, which is register.
So let's replace this code with wire:submit.prevent. And we're going to use the name of the method we want to call, which is register. And what this is doing is when the form is submitted, either when you click a submit button or you click enter is it's going to call this register method, because that's what we defined right here. Now when I'm building Livewire components, I usually like to split my screen so I can see the component and the Blade template at the same time. So let's just make sure this is working. Let's dd. If we reload the page and click register, let's put something there.
Let's die and dump. If we reload the page and click register, let's put something there. Looks like that's still an email field. So for company name, this type should be text. All right, let's refresh. Put something in there. And everything seems to be working. So now let's model up these inputs. So let's say wire:model is name. And let's model up the rest of the variables really quickly.
So let's say wire:model is name. And let's model up the rest of the variables really quickly. Because this is a form, the submit button will work without a click handler. Now we just need to get rid of the dd and try again. And we're getting an error because our Tenant model doesn't allow the name to be fillable. So let's go to the Tenant model. And let's try one more time. And again, it looks like we have a guarded issue. So let's go here. Let's find the User model.
So let's go here. Let's find the User model. And here we have fillable. So let's just change this to guarded and leave it blank. One more time. So it doesn't seem to work, but I think that's because I'm getting a validation error. So let's go ahead and throw the error bag onto the screen and see if that's correct. So obviously this is not how we want to handle our errors, but we will address that in the next video. Let's just get this form submitted and make sure it works.
next video. Let's just get this form submitted and make sure it works. Okay, and looks like the submission finally worked. So let's go ahead and look at the database. We've got the record here at the bottom. You can see the final record number 22 is the one I just put in and the tenant_id is 17. So if we go look at the tenants table, you can see test company one is the tenant that I just submitted. So now our pre-logged in pages are basically done, but we do still have that validation.
I just submitted. So now our pre-logged in pages are basically done, but we do still have that validation issue that I want to go back and fix in the next video. And we're going to do that by building a Livewire Blade component.
