This recipe demonstrates the use of MoonShine not as an admin panel, but as a personal account under the User model with login, registration, password recovery, and profile (basic set).
A good example of working with different Layouts for different pages.
We will have pages with forms for login, registration, and password recovery, and they will differ in template from the user profile page, so we need to create 2 templates:
AppLayout - for the profile
FormLayout - for authentication
AppLayout
Let's start by executing the command to create the template
php artisan moonshine:layout AppLayout --compact
phpartisanmoonshine:layoutAppLayout--compact
php artisan moonshine:layout AppLayout --compact
Next, we will assemble the constructor from the components we need
namespace App\MoonShine\Layouts;
use App\MoonShine\Resources\PackageCategoryResource;
use App\MoonShine\Resources\PackageResource;
use App\MoonShine\Resources\UserResource;
use MoonShine\ColorManager\ColorManager;
use MoonShine\Contracts\ColorManager\ColorManagerContract;
use MoonShine\Laravel\Layouts\CompactLayout;
use MoonShine\MenuManager\MenuGroup;
use MoonShine\MenuManager\MenuItem;
use MoonShine\UI\Components\{Components,
Layout\Div,
Layout\Body,
Layout\Content,
Layout\Flash,
Layout\Html,
Layout\Layout,
Layout\Wrapper};
final class AppLayout extends CompactLayout
{
protected function getHomeUrl(): string
{
return route('home');
}
public function build(): Layout
{
return Layout::make([
Html::make([
$this->getHeadComponent(),
Body::make([
Wrapper::make([
Div::make([
Flash::make(),
Content::make([
Components::make(
$this->getPage()->getComponents()
),
]),
])->class('layout-page'),
]),
])->class('theme-minimalistic'),
])
->customAttributes([
'lang' => $this->getHeadLang(),
])
->withAlpineJs()
->withThemes(),
]);
}
}
namespace App\Http\Controllers;
use App\Http\Requests\AuthenticateFormRequest;
use App\Models\User;
use App\MoonShine\Pages\LoginPage;
use Illuminate\Container\Attributes\Auth;
use Illuminate\Container\Attributes\Authenticated;
use Illuminate\Container\Attributes\CurrentUser;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
final class AuthenticateController extends Controller
{
public function form(LoginPage $page): LoginPage
{
return $page;
}
public function authenticate(AuthenticateFormRequest $request): RedirectResponse
{
if (!auth()->attempt($request->validated())) {
return back()->withErrors([
'email' => __('moonshine::auth.failed')
]);
}
return redirect()->intended(
route('profile')
);
}
public function logout(
#[Auth]
Guard $guard,
Request $request
): RedirectResponse {
$guard->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect()->intended(
url()->previous() ?? route('home')
);
}
}
namespace App\Http\Controllers;
use App\Http\Requests\AuthenticateFormRequest;
use App\Models\User;
use App\MoonShine\Pages\LoginPage;
use Illuminate\Container\Attributes\Auth;
use Illuminate\Container\Attributes\Authenticated;
use Illuminate\Container\Attributes\CurrentUser;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
final class AuthenticateController extends Controller
{
public function form(LoginPage $page): LoginPage
{
return $page;
}
public function authenticate(AuthenticateFormRequest $request): RedirectResponse
{
if (!auth()->attempt($request->validated())) {
return back()->withErrors([
'email' => __('moonshine::auth.failed')
]);
}
return redirect()->intended(
route('profile')
);
}
public function logout(
#[Auth]
Guard $guard,
Request $request
): RedirectResponse {
$guard->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect()->intended(
url()->previous() ?? route('home')
);
}
}
Note how we render pages in controllers:
public function form(LoginPage $page): LoginPage
{
return $page;
}
publicfunctionform(LoginPage $page):LoginPage
{
return $page;
}
public function form(LoginPage $page): LoginPage
{
return $page;
}
I will also provide the FormRequest classes so that the recipe is as complete as possible.
guest();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules(): array
{
return [
'email' => ['required'],
'password' => ['required', Password::default()],
];
}
}
<?php
namespace App\Http\Requests;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Password;
class AuthenticateFormRequest extends FormRequest
{
public function authorize(): bool
{
return auth()->guest();
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, ValidationRule|array|string>
*/
public function rules(): array
{
return [
'email' => ['required'],
'password' => ['required', Password::default()],
];
}
}
ForgotController
only('email')
);
if ($status === Password::RESET_LINK_SENT) {
MoonShineUI::toast(__('If the account exists, then the instructions are sent to your email'));
}
return $status === Password::RESET_LINK_SENT
? back()->with(['alert' => __($status)])
: back()->withErrors(['email' => __($status)]);
}
public function updatePassword(ResetPasswordFormRequest $request): RedirectResponse
{
$status = Password::reset(
$request->only('email', 'password', 'password_confirmation', 'token'),
static function (User $user, string $password) {
$user->forceFill([
'password' => Hash::make($password),
])->setRememberToken(Str::random(60));
$user->save();
event(new PasswordReset($user));
}
);
return $status === Password::PASSWORD_RESET
? redirect()->route('login')->with('alert', __($status))
: back()->withErrors(['email' => [__($status)]]);
}
}
<?php
namespace App\Http\Controllers;
use App\Http\Requests\ForgotPasswordFormRequest;
use App\Http\Requests\ResetPasswordFormRequest;
use App\Models\User;
use App\MoonShine\Pages\ForgotPage;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;
use MoonShine\Laravel\MoonShineUI;
class ForgotController extends Controller
{
public function form(ForgotPage $page): ForgotPage
{
return $page;
}
public function reset(ForgotPasswordFormRequest $request): RedirectResponse
{
$status = Password::sendResetLink(
$request->only('email')
);
if ($status === Password::RESET_LINK_SENT) {
MoonShineUI::toast(__('If the account exists, then the instructions are sent to your email'));
}
return $status === Password::RESET_LINK_SENT
? back()->with(['alert' => __($status)])
: back()->withErrors(['email' => __($status)]);
}
public function updatePassword(ResetPasswordFormRequest $request): RedirectResponse
{
$status = Password::reset(
$request->only('email', 'password', 'password_confirmation', 'token'),
static function (User $user, string $password) {
$user->forceFill([
'password' => Hash::make($password),
])->setRememberToken(Str::random(60));
$user->save();
event(new PasswordReset($user));
}
);
return $status === Password::PASSWORD_RESET
? redirect()->route('login')->with('alert', __($status))
: back()->withErrors(['email' => [__($status)]]);
}
}
guest();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules(): array
{
return [
'email' => ['required', 'email:dns'],
];
}
}
<?php
namespace App\Http\Requests;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
class ForgotPasswordFormRequest extends FormRequest
{
public function authorize(): bool
{
return auth()->guest();
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, ValidationRule|array|string>
*/
public function rules(): array
{
return [
'email' => ['required', 'email:dns'],
];
}
}
guest();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules(): array
{
return [
'token' => 'required',
'email' => ['required', 'email'],
'password' => ['required', 'confirmed', PasswordRules::default()],
];
}
}
<?php
namespace App\Http\Requests;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Password as PasswordRules;
class ResetPasswordFormRequest extends FormRequest
{
public function authorize(): bool
{
return auth()->guest();
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, ValidationRule|array|string>
*/
public function rules(): array
{
return [
'token' => 'required',
'email' => ['required', 'email'],
'password' => ['required', 'confirmed', PasswordRules::default()],
];
}
}
ProfileController
namespace App\Http\Controllers;
use App\Http\Requests\ProfileFormRequest;
use App\Models\User;
use App\MoonShine\Pages\ProfilePage;
use Illuminate\Container\Attributes\CurrentUser;
use Illuminate\Support\Facades\Hash;
use Symfony\Component\HttpFoundation\RedirectResponse;
final class ProfileController extends Controller
{
public function index(
ProfilePage $page
): ProfilePage {
return $page;
}
public function update(
ProfileFormRequest $request,
#[CurrentUser] User $user
): RedirectResponse
{
$data = $request->only(['email', 'name']);
if ($request->filled('password')) {
$data['password'] = Hash::make($request->input('password'));
}
$user->update($data);
return to_route('profile');
}
}
namespace App\Http\Controllers;
use App\Http\Requests\ProfileFormRequest;
use App\Models\User;
use App\MoonShine\Pages\ProfilePage;
use Illuminate\Container\Attributes\CurrentUser;
use Illuminate\Support\Facades\Hash;
use Symfony\Component\HttpFoundation\RedirectResponse;
final class ProfileController extends Controller
{
public function index(
ProfilePage $page
): ProfilePage {
return $page;
}
public function update(
ProfileFormRequest $request,
#[CurrentUser] User $user
): RedirectResponse
{
$data = $request->only(['email', 'name']);
if ($request->filled('password')) {
$data['password'] = Hash::make($request->input('password'));
}
$user->update($data);
return to_route('profile');
}
}
check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules(): array
{
return [
'name' => ['required'],
'email' => ['required', 'email:dns', Rule::unique('users')->ignore(auth()->id())],
'password' => ['confirmed'],
];
}
}
<?php
namespace App\Http\Requests;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class ProfileFormRequest extends FormRequest
{
public function authorize(): bool
{
return auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, ValidationRule|array|string>
*/
public function rules(): array
{
return [
'name' => ['required'],
'email' => ['required', 'email:dns', Rule::unique('users')->ignore(auth()->id())],
'password' => ['confirmed'],
];
}
}
RegisterController
namespace App\Http\Controllers;
use App\Http\Requests\RegisterFormRequest;
use App\Models\User;
use App\MoonShine\Pages\RegisterPage;
use Illuminate\Http\RedirectResponse;
final class RegisterController extends Controller
{
public function form(RegisterPage $page): RegisterPage
{
return $page;
}
public function store(RegisterFormRequest $request): RedirectResponse
{
$user = User::query()->create(
$request->validated()
);
auth()->login($user);
return redirect()->intended(
route('home')
);
}
}
namespace App\Http\Controllers;
use App\Http\Requests\RegisterFormRequest;
use App\Models\User;
use App\MoonShine\Pages\RegisterPage;
use Illuminate\Http\RedirectResponse;
final class RegisterController extends Controller
{
public function form(RegisterPage $page): RegisterPage
{
return $page;
}
public function store(RegisterFormRequest $request): RedirectResponse
{
$user = User::query()->create(
$request->validated()
);
auth()->login($user);
return redirect()->intended(
route('home')
);
}
}
guest();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules(): array
{
return [
'name' => ['required'],
'email' => ['required', 'email:dns', Rule::unique('users')],
'password' => ['required', 'confirmed'],
];
}
}
<?php
namespace App\Http\Requests;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class RegisterFormRequest extends FormRequest
{
public function authorize(): bool
{
return auth()->guest();
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, ValidationRule|array|string>
*/
public function rules(): array
{
return [
'name' => ['required'],
'email' => ['required', 'email:dns', Rule::unique('users')],
'password' => ['required', 'confirmed'],
];
}
}
That's it! MoonShine does not limit you to just an admin panel, as it is a full-fledged UI kit.