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_KEY=
|
||||
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\UpdateUserPassword;
|
||||
use App\Actions\Fortify\UpdateUserProfileInformation;
|
||||
use App\Livewire\Auth\Login;
|
||||
use Illuminate\Cache\RateLimiting\Limit;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
|
@ -42,5 +43,9 @@ class FortifyServiceProvider extends ServiceProvider
|
|||
RateLimiter::for('two-factor', function (Request $request) {
|
||||
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">
|
||||
<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 ">
|
||||
app
|
||||
{{ config('app.name') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -13,7 +13,7 @@ return [
|
|||
|
|
||||
*/
|
||||
|
||||
'name' => env('APP_NAME', 'Laravel'),
|
||||
'name' => env('APP_NAME', 'XBackBone'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
|
@ -1,23 +1,14 @@
|
|||
<!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'])
|
||||
</head>
|
||||
<body class="min-h-screen font-sans antialiased bg-base-200/50 dark:bg-base-200">
|
||||
@extends('components.layouts.base')
|
||||
|
||||
@section('body')
|
||||
{{-- NAVBAR mobile only --}}
|
||||
<x-nav sticky class="lg:hidden">
|
||||
<x-slot:brand>
|
||||
<x-app-brand />
|
||||
<x-app-brand/>
|
||||
</x-slot:brand>
|
||||
<x-slot:actions>
|
||||
<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>
|
||||
</x-slot:actions>
|
||||
</x-nav>
|
||||
|
@ -28,28 +19,28 @@
|
|||
<x-slot:sidebar drawer="main-drawer" collapsible class="bg-base-100 lg:bg-inherit">
|
||||
|
||||
{{-- BRAND --}}
|
||||
<x-app-brand class="p-5 pt-3" />
|
||||
<x-app-brand class="p-5 pt-3"/>
|
||||
|
||||
{{-- MENU --}}
|
||||
<x-menu activate-by-route>
|
||||
|
||||
{{-- 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-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-list-item>
|
||||
|
||||
<x-menu-separator />
|
||||
<x-menu-separator/>
|
||||
@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-item title="Wifi" icon="o-wifi" link="####" />
|
||||
<x-menu-item title="Archives" icon="o-archive-box" link="####" />
|
||||
<x-menu-item title="Wifi" icon="o-wifi" link="####"/>
|
||||
<x-menu-item title="Archives" icon="o-archive-box" link="####"/>
|
||||
</x-menu-sub>
|
||||
</x-menu>
|
||||
</x-slot:sidebar>
|
||||
|
@ -61,6 +52,5 @@
|
|||
</x-main>
|
||||
|
||||
{{-- TOAST area --}}
|
||||
<x-toast />
|
||||
</body>
|
||||
</html>
|
||||
<x-toast/>
|
||||
@endsection
|
||||
|
|
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>
|
||||
<!-- HEADER -->
|
||||
<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>
|
||||
feefefef
|
||||
</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
|
||||
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