Added login form
This commit is contained in:
parent
eb656afe06
commit
c981498810
14 changed files with 204 additions and 228 deletions
|
@ -1,4 +1,3 @@
|
||||||
APP_NAME=Laravel
|
|
||||||
APP_ENV=local
|
APP_ENV=local
|
||||||
APP_KEY=
|
APP_KEY=
|
||||||
APP_DEBUG=true
|
APP_DEBUG=true
|
||||||
|
|
27
core/app/Livewire/Auth/Login.php
Normal file
27
core/app/Livewire/Auth/Login.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Auth;
|
||||||
|
|
||||||
|
use App\Livewire\Forms\LoginForm;
|
||||||
|
use Livewire\Component;
|
||||||
|
use Mary\Traits\Toast;
|
||||||
|
|
||||||
|
class Login extends Component
|
||||||
|
{
|
||||||
|
use Toast;
|
||||||
|
|
||||||
|
public LoginForm $form;
|
||||||
|
|
||||||
|
public function authenticate()
|
||||||
|
{
|
||||||
|
$this->validate();
|
||||||
|
|
||||||
|
$this->form->authenticate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.auth.login')
|
||||||
|
->layout('components.layouts.auth', ['title' => 'Login']);
|
||||||
|
}
|
||||||
|
}
|
72
core/app/Livewire/Forms/LoginForm.php
Normal file
72
core/app/Livewire/Forms/LoginForm.php
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Forms;
|
||||||
|
|
||||||
|
use Illuminate\Auth\Events\Lockout;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\RateLimiter;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use Livewire\Attributes\Validate;
|
||||||
|
use Livewire\Form;
|
||||||
|
|
||||||
|
class LoginForm extends Form
|
||||||
|
{
|
||||||
|
#[Validate('required|string|email')]
|
||||||
|
public string $email = '';
|
||||||
|
|
||||||
|
#[Validate('required|string')]
|
||||||
|
public string $password = '';
|
||||||
|
|
||||||
|
#[Validate('boolean')]
|
||||||
|
public bool $remember = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to authenticate the request's credentials.
|
||||||
|
*
|
||||||
|
* @throws \Illuminate\Validation\ValidationException
|
||||||
|
*/
|
||||||
|
public function authenticate(): void
|
||||||
|
{
|
||||||
|
$this->ensureIsNotRateLimited();
|
||||||
|
|
||||||
|
if (!Auth::attempt($this->only(['email', 'password']), $this->remember)) {
|
||||||
|
RateLimiter::hit($this->throttleKey());
|
||||||
|
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
'form.email' => trans('auth.failed'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
RateLimiter::clear($this->throttleKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure the authentication request is not rate limited.
|
||||||
|
*/
|
||||||
|
protected function ensureIsNotRateLimited(): void
|
||||||
|
{
|
||||||
|
if (!RateLimiter::tooManyAttempts($this->throttleKey(), 5)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event(new Lockout(request()));
|
||||||
|
|
||||||
|
$seconds = RateLimiter::availableIn($this->throttleKey());
|
||||||
|
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
'form.email' => trans('auth.throttle', [
|
||||||
|
'seconds' => $seconds,
|
||||||
|
'minutes' => ceil($seconds / 60),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the authentication rate limiting throttle key.
|
||||||
|
*/
|
||||||
|
protected function throttleKey(): string
|
||||||
|
{
|
||||||
|
return Str::transliterate(Str::lower($this->email).'|'.request()->ip());
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ use App\Actions\Fortify\CreateNewUser;
|
||||||
use App\Actions\Fortify\ResetUserPassword;
|
use App\Actions\Fortify\ResetUserPassword;
|
||||||
use App\Actions\Fortify\UpdateUserPassword;
|
use App\Actions\Fortify\UpdateUserPassword;
|
||||||
use App\Actions\Fortify\UpdateUserProfileInformation;
|
use App\Actions\Fortify\UpdateUserProfileInformation;
|
||||||
|
use App\Livewire\Auth\Login;
|
||||||
use Illuminate\Cache\RateLimiting\Limit;
|
use Illuminate\Cache\RateLimiting\Limit;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\RateLimiter;
|
use Illuminate\Support\Facades\RateLimiter;
|
||||||
|
@ -42,5 +43,9 @@ class FortifyServiceProvider extends ServiceProvider
|
||||||
RateLimiter::for('two-factor', function (Request $request) {
|
RateLimiter::for('two-factor', function (Request $request) {
|
||||||
return Limit::perMinute(5)->by($request->session()->get('login.id'));
|
return Limit::perMinute(5)->by($request->session()->get('login.id'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Fortify::loginView(static function () {
|
||||||
|
return app()->call(Login::class);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ class AppBrand extends Component
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<x-icon name="o-square-3-stack-3d" class="w-6 -mb-1 text-purple-500" />
|
<x-icon name="o-square-3-stack-3d" class="w-6 -mb-1 text-purple-500" />
|
||||||
<span class="font-bold text-3xl me-3 bg-gradient-to-r from-purple-500 to-pink-300 bg-clip-text text-transparent ">
|
<span class="font-bold text-3xl me-3 bg-gradient-to-r from-purple-500 to-pink-300 bg-clip-text text-transparent ">
|
||||||
app
|
{{ config('app.name') }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -13,7 +13,7 @@ return [
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'name' => env('APP_NAME', 'Laravel'),
|
'name' => env('APP_NAME', 'XBackBone'),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
@ -1,23 +1,14 @@
|
||||||
<!DOCTYPE html>
|
@extends('components.layouts.base')
|
||||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover">
|
|
||||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
|
||||||
<title>{{ isset($title) ? $title.' - '.config('app.name') : config('app.name') }}</title>
|
|
||||||
|
|
||||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
|
||||||
</head>
|
|
||||||
<body class="min-h-screen font-sans antialiased bg-base-200/50 dark:bg-base-200">
|
|
||||||
|
|
||||||
|
@section('body')
|
||||||
{{-- NAVBAR mobile only --}}
|
{{-- NAVBAR mobile only --}}
|
||||||
<x-nav sticky class="lg:hidden">
|
<x-nav sticky class="lg:hidden">
|
||||||
<x-slot:brand>
|
<x-slot:brand>
|
||||||
<x-app-brand />
|
<x-app-brand/>
|
||||||
</x-slot:brand>
|
</x-slot:brand>
|
||||||
<x-slot:actions>
|
<x-slot:actions>
|
||||||
<label for="main-drawer" class="lg:hidden me-3">
|
<label for="main-drawer" class="lg:hidden me-3">
|
||||||
<x-icon name="o-bars-3" class="cursor-pointer" />
|
<x-icon name="o-bars-3" class="cursor-pointer"/>
|
||||||
</label>
|
</label>
|
||||||
</x-slot:actions>
|
</x-slot:actions>
|
||||||
</x-nav>
|
</x-nav>
|
||||||
|
@ -28,28 +19,28 @@
|
||||||
<x-slot:sidebar drawer="main-drawer" collapsible class="bg-base-100 lg:bg-inherit">
|
<x-slot:sidebar drawer="main-drawer" collapsible class="bg-base-100 lg:bg-inherit">
|
||||||
|
|
||||||
{{-- BRAND --}}
|
{{-- BRAND --}}
|
||||||
<x-app-brand class="p-5 pt-3" />
|
<x-app-brand class="p-5 pt-3"/>
|
||||||
|
|
||||||
{{-- MENU --}}
|
{{-- MENU --}}
|
||||||
<x-menu activate-by-route>
|
<x-menu activate-by-route>
|
||||||
|
|
||||||
{{-- User --}}
|
{{-- User --}}
|
||||||
@if($user = auth()->user())
|
@if($user = auth()->user())
|
||||||
<x-menu-separator />
|
<x-menu-separator/>
|
||||||
|
|
||||||
<x-list-item :item="$user" value="name" sub-value="email" no-separator no-hover class="-mx-2 !-my-2 rounded">
|
<x-list-item :item="$user" value="name" sub-value="email" no-separator no-hover class="-mx-2 !-my-2 rounded">
|
||||||
<x-slot:actions>
|
<x-slot:actions>
|
||||||
<x-button icon="o-power" class="btn-circle btn-ghost btn-xs" tooltip-left="logoff" no-wire-navigate link="/logout" />
|
<x-button icon="o-power" class="btn-circle btn-ghost btn-xs" tooltip-left="logoff" no-wire-navigate link="/logout"/>
|
||||||
</x-slot:actions>
|
</x-slot:actions>
|
||||||
</x-list-item>
|
</x-list-item>
|
||||||
|
|
||||||
<x-menu-separator />
|
<x-menu-separator/>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<x-menu-item title="Hello" icon="o-sparkles" link="/" />
|
<x-menu-item title="Hello" icon="o-sparkles" link="/"/>
|
||||||
<x-menu-sub title="Settings" icon="o-cog-6-tooth">
|
<x-menu-sub title="Settings" icon="o-cog-6-tooth">
|
||||||
<x-menu-item title="Wifi" icon="o-wifi" link="####" />
|
<x-menu-item title="Wifi" icon="o-wifi" link="####"/>
|
||||||
<x-menu-item title="Archives" icon="o-archive-box" link="####" />
|
<x-menu-item title="Archives" icon="o-archive-box" link="####"/>
|
||||||
</x-menu-sub>
|
</x-menu-sub>
|
||||||
</x-menu>
|
</x-menu>
|
||||||
</x-slot:sidebar>
|
</x-slot:sidebar>
|
||||||
|
@ -61,6 +52,5 @@
|
||||||
</x-main>
|
</x-main>
|
||||||
|
|
||||||
{{-- TOAST area --}}
|
{{-- TOAST area --}}
|
||||||
<x-toast />
|
<x-toast/>
|
||||||
</body>
|
@endsection
|
||||||
</html>
|
|
||||||
|
|
14
core/resources/views/components/layouts/auth.blade.php
Normal file
14
core/resources/views/components/layouts/auth.blade.php
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
@extends('components.layouts.base')
|
||||||
|
|
||||||
|
@section('body')
|
||||||
|
<div class="grid h-screen place-items-center">
|
||||||
|
<div class="relative flex flex-col items-center justify-center h-screen overflow-hidden w-96">
|
||||||
|
<x-card shadow class="w-96 pr-8 pl-8">
|
||||||
|
<h1 class="text-3xl font-semibold text-center mb-4">
|
||||||
|
{{ config('app.name') }}
|
||||||
|
</h1>
|
||||||
|
{{ $slot }}
|
||||||
|
</x-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
16
core/resources/views/components/layouts/base.blade.php
Normal file
16
core/resources/views/components/layouts/base.blade.php
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover">
|
||||||
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
|
<title>{{ isset($title) ? $title.' - '.config('app.name') : config('app.name') }}</title>
|
||||||
|
|
||||||
|
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||||
|
@livewireStyles
|
||||||
|
</head>
|
||||||
|
<body class="min-h-screen font-sans antialiased bg-base-200/50 dark:bg-base-200">
|
||||||
|
@yield('body')
|
||||||
|
@livewireScripts
|
||||||
|
</body>
|
||||||
|
</html>
|
13
core/resources/views/livewire/auth/login.blade.php
Normal file
13
core/resources/views/livewire/auth/login.blade.php
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<div>
|
||||||
|
<x-form wire:submit="authenticate" no-separator>
|
||||||
|
<x-input label="Username" type="email" wire:model="form.email" inline/>
|
||||||
|
<x-input label="Password" type="password" wire:model="form.password" inline/>
|
||||||
|
<x-checkbox label="Remember me" wire:model="form.remember"/>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-2 mt-6">
|
||||||
|
<x-button label="Login" class="btn-primary btn-block" type="submit" spinner="authenticate"/>
|
||||||
|
<x-button label="Register" class="btn-block"/>
|
||||||
|
<x-button label="Forgot Password?" class="btn-link btn-sm"/>
|
||||||
|
</div>
|
||||||
|
</x-form>
|
||||||
|
</div>
|
|
@ -1,30 +1,3 @@
|
||||||
<div>
|
<div>
|
||||||
<!-- HEADER -->
|
feefefef
|
||||||
<x-header title="Hello" separator progress-indicator>
|
|
||||||
<x-slot:middle class="!justify-end">
|
|
||||||
<x-input placeholder="Search..." wire:model.live.debounce="search" clearable icon="o-magnifying-glass" />
|
|
||||||
</x-slot:middle>
|
|
||||||
<x-slot:actions>
|
|
||||||
<x-button label="Filters" @click="$wire.drawer = true" responsive icon="o-funnel" class="btn-primary" />
|
|
||||||
</x-slot:actions>
|
|
||||||
</x-header>
|
|
||||||
|
|
||||||
<!-- TABLE -->
|
|
||||||
<x-card>
|
|
||||||
<x-table :headers="$headers" :rows="$users" :sort-by="$sortBy">
|
|
||||||
@scope('actions', $user)
|
|
||||||
<x-button icon="o-trash" wire:click="delete({{ $user['id'] }})" spinner class="btn-ghost btn-sm text-red-500" />
|
|
||||||
@endscope
|
|
||||||
</x-table>
|
|
||||||
</x-card>
|
|
||||||
|
|
||||||
<!-- FILTER DRAWER -->
|
|
||||||
<x-drawer wire:model="drawer" title="Filters" right separator with-close-button class="lg:w-1/3">
|
|
||||||
<x-input placeholder="Search..." wire:model.live.debounce="search" icon="o-magnifying-glass" @keydown.enter="$wire.drawer = false" />
|
|
||||||
|
|
||||||
<x-slot:actions>
|
|
||||||
<x-button label="Reset" icon="o-x-mark" wire:click="clear" spinner />
|
|
||||||
<x-button label="Done" icon="o-check" class="btn-primary" @click="$wire.drawer = false" />
|
|
||||||
</x-slot:actions>
|
|
||||||
</x-drawer>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -14,4 +14,6 @@ use Illuminate\Support\Facades\Route;
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Route::get('/', Welcome::class);
|
Route::redirect('/', '/dashboard');
|
||||||
|
|
||||||
|
Route::get('/dashboard', Welcome::class);
|
||||||
|
|
|
@ -15,5 +15,42 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
// Add daisyUI
|
// Add daisyUI
|
||||||
plugins: [require("daisyui")]
|
plugins: [require("daisyui")],
|
||||||
|
|
||||||
|
daisyui: {
|
||||||
|
themes: [
|
||||||
|
"light",
|
||||||
|
"dark",
|
||||||
|
"cupcake",
|
||||||
|
"bumblebee",
|
||||||
|
"emerald",
|
||||||
|
"corporate",
|
||||||
|
"synthwave",
|
||||||
|
"retro",
|
||||||
|
"cyberpunk",
|
||||||
|
"valentine",
|
||||||
|
"halloween",
|
||||||
|
"garden",
|
||||||
|
"forest",
|
||||||
|
"aqua",
|
||||||
|
"lofi",
|
||||||
|
"pastel",
|
||||||
|
"fantasy",
|
||||||
|
"wireframe",
|
||||||
|
"black",
|
||||||
|
"luxury",
|
||||||
|
"dracula",
|
||||||
|
"cmyk",
|
||||||
|
"autumn",
|
||||||
|
"business",
|
||||||
|
"acid",
|
||||||
|
"lemonade",
|
||||||
|
"night",
|
||||||
|
"coffee",
|
||||||
|
"winter",
|
||||||
|
"dim",
|
||||||
|
"nord",
|
||||||
|
"sunset",
|
||||||
|
],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue