Added login form

This commit is contained in:
Sergio Brighenti 2024-08-24 13:22:35 +02:00
parent eb656afe06
commit c981498810
14 changed files with 204 additions and 228 deletions

View file

@ -1,4 +1,3 @@
APP_NAME=Laravel
APP_ENV=local APP_ENV=local
APP_KEY= APP_KEY=
APP_DEBUG=true APP_DEBUG=true

View 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']);
}
}

View 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());
}
}

View file

@ -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);
});
} }
} }

View file

@ -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>

View file

@ -13,7 +13,7 @@ return [
| |
*/ */
'name' => env('APP_NAME', 'Laravel'), 'name' => env('APP_NAME', 'XBackBone'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------

View file

@ -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>

View 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

View 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>

View 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>

View file

@ -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

View file

@ -14,4 +14,6 @@ use Illuminate\Support\Facades\Route;
| |
*/ */
Route::get('/', Welcome::class); Route::redirect('/', '/dashboard');
Route::get('/dashboard', Welcome::class);

View file

@ -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",
],
},
} }