Skip to content
This repository has been archived by the owner on Apr 11, 2024. It is now read-only.

Commit

Permalink
Add Authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
francoism90 authored Jan 7, 2024
1 parent 665aa94 commit 32b3ea9
Show file tree
Hide file tree
Showing 35 changed files with 378 additions and 114 deletions.
10 changes: 9 additions & 1 deletion resources/css/components/input.css
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
@layer components {
.field {
@apply w-full;
}

.label {
@apply block;
}

.input {
@apply w-full border-0 border-opacity-0 bg-transparent focus:border-transparent focus:ring-0;
@apply w-full focus:border-transparent focus:ring-0;

&-group {
@apply flex flex-1 items-center;
Expand All @@ -17,6 +21,10 @@
&-append {
@apply rounded-r-none;
}

&-ghost {
@apply border-0 border-opacity-0 bg-transparent;
}
}

.radio {
Expand Down
24 changes: 24 additions & 0 deletions resources/views/auth/login.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<x-ui-container class="flex h-screen items-center justify-center">
<x-ui-card>
<form wire:submit="submit">
<x-forms-input
wire:model="form.email"
type="email"
label="{{ __('Email') }}"
required
autofocus
/>

<x-forms-input
wire:model="form.password"
type="password"
label="{{ __('Password') }}"
required
/>

<x-ui-button type="submit">
{{ __('Login') }}
</x-ui-button>
</form>
</x-ui-card>
</x-ui-container>
8 changes: 0 additions & 8 deletions resources/views/forms/form.blade.php

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<div
wire:key="{{ $hash() }}"
class="w-full"
class="field"
>
@if ($label)
<x-forms-label
{{ $attributes->only('required') }}
for="{{ $id() }}"
:$label
/>
Expand Down
2 changes: 1 addition & 1 deletion resources/views/forms/label.blade.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<label class="label">
<span>{{ $label }}</span>

@if ($attributes->get('required'))
@if ($required)
<span class="text-error">*</span>
@endif
</label>
5 changes: 5 additions & 0 deletions resources/views/ui/card.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div class="card">
{{ $slot }}

{{ $actions }}
</div>
30 changes: 30 additions & 0 deletions src/Auth/Controllers/LoginController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Foxws\LivewireUse\Auth\Controllers;

use Foxws\LivewireUse\Auth\Forms\LoginForm;
use Foxws\LivewireUse\Views\Components\Page;
use Livewire\Attributes\Layout;

#[Layout('components.layouts.auth')]
class LoginController extends Page
{
protected static string $view = 'auth.login';

public LoginForm $form;

public function mount(): void
{
$this->seo()->setTitle(__('Login'));
$this->seo()->setDescription(__('Login to Account'));

if (static::isAuthenticated()) {
redirect()->intended();
}
}

public function submit(): void
{
$this->form->submit();
}
}
41 changes: 41 additions & 0 deletions src/Auth/Forms/LoginForm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace Foxws\LivewireUse\Auth\Forms;

use Foxws\LivewireUse\Forms\Components\Form;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rules\Password;
use Livewire\Attributes\Validate;

class LoginForm extends Form
{
protected static int $maxAttempts = 5;

#[Validate]
public ?string $email = null;

#[Validate]
public ?string $password = null;

public function rules(): array
{
return [
'email' => 'required|email',
'password' => [
'required',
Password::defaults(),
],
];
}

protected function handle()
{
if (Auth::attempt($this->all())) {
session()->regenerate();

return redirect()->intended();
}

$this->addError('email', __('These credentials do not match our records'));
}
}
23 changes: 23 additions & 0 deletions src/Exceptions/RateLimitedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Foxws\LivewireUse\Exceptions;

use Exception;

class RateLimitedException extends Exception
{
public int $minutesUntilAvailable = 0;

public function __construct(
public string $ip,
public int $secondsUntilAvailable,
) {
$this->minutesUntilAvailable = ceil($this->secondsUntilAvailable / 60);

parent::__construct(sprintf(
'Too many requests from [%s]. Retry in %d seconds.',
$this->ip,
$this->secondsUntilAvailable,
));
}
}
44 changes: 25 additions & 19 deletions src/Forms/Components/Form.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

namespace Foxws\LivewireUse\Forms\Components;

use Foxws\LivewireUse\Exceptions\RateLimitedException;
use Foxws\LivewireUse\Forms\Concerns\WithSession;
use Foxws\LivewireUse\Forms\Concerns\WithThrottle;
use Foxws\LivewireUse\Forms\Concerns\WithValidation;
use Foxws\LivewireUse\Views\Concerns\WithAuthorization;
use Foxws\LivewireUse\Views\Concerns\WithHooks;
use Livewire\Form as BaseForm;
Expand All @@ -12,35 +15,33 @@ abstract class Form extends BaseForm
use WithAuthorization;
use WithHooks;
use WithSession;

protected static bool $recoverable = false;
use WithThrottle;
use WithValidation;

public function submit(): void
{
$this->callHook('beforeValidate');
try {
$this->rateLimit();

$this->check();
$this->callHook('beforeValidate');

$this->callHook('afterValidate');
$this->check();

$this->store();
$this->callHook('afterValidate');

$this->callHook('afterSubmit');
}
$this->store();

public function check(): void
{
if (! static::$recoverable) {
$this->validate();
$this->handle();

return;
$this->callHook('afterHandle');
} catch (RateLimitedException $e) {
$this->handleThrottle($e);
}
}

rescue(
fn () => $this->validate(),
fn () => $this->reset(),
report: false
);
protected function handle()
{
//
}

public function has(string $name): bool
Expand All @@ -50,6 +51,11 @@ public function has(string $name): bool

public function get(string $name, mixed $default = null): mixed
{
return $this->getPropertyValue($name) ?? $default;
return $this->getPropertyValue($name) ?: $default;
}

public function filled(string $name): bool
{
return filled($this->get($name));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

use Illuminate\Contracts\Support\Htmlable;

class TextInput extends Field
class Input extends Field
{
protected static string $view = 'forms.text-input';
protected static string $view = 'forms.input';

public function __construct(
public string|Htmlable|null $label = null,
Expand Down
7 changes: 1 addition & 6 deletions src/Forms/Components/Label.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,15 @@
namespace Foxws\LivewireUse\Forms\Components;

use Illuminate\Contracts\Support\Htmlable;
use Illuminate\View\View;

class Label extends Field
{
protected static string $view = 'forms.label';

public function __construct(
public string|Htmlable|null $label = null,
public bool $required = false,
public bool $inline = false,
) {
}

public function render(): View
{
return view(static::$view);
}
}
29 changes: 29 additions & 0 deletions src/Forms/Concerns/WithThrottle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Foxws\LivewireUse\Forms\Concerns;

use Foxws\LivewireUse\Exceptions\RateLimitedException;
use Foxws\LivewireUse\Views\Concerns\WithRateLimiting;

trait WithThrottle
{
use WithRateLimiting;

protected function handleThrottle(RateLimitedException $e): void
{
$field = $this->getThrottleModel();

$this->resetErrorBag($field);

$this->addError($field, __('Please retry in :seconds seconds', [
'seconds' => $e->secondsUntilAvailable ?? 0,
]));
}

protected function getThrottleModel(): string
{
$fields = array_keys($this->all());

return $fields[0] ?? 'throttled';
}
}
22 changes: 22 additions & 0 deletions src/Forms/Concerns/WithValidation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Foxws\LivewireUse\Forms\Concerns;

trait WithValidation
{
protected static bool $recoverable = false;

public function check(): void
{
if (! static::$recoverable) {
$this->validate();

return;
}

rescue(
fn () => $this->validate(),
fn () => $this->reset(),
);
}
}
Loading

0 comments on commit 32b3ea9

Please sign in to comment.