feat: approve/reject quotes
This commit is contained in:
parent
a918600813
commit
1833146158
33
app/Models/RequestedQuote.php
Normal file
33
app/Models/RequestedQuote.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
class RequestedQuote extends Model
|
||||||
|
{
|
||||||
|
use SoftDeletes;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'quote',
|
||||||
|
'user_id',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function approve(): void
|
||||||
|
{
|
||||||
|
// TODO: we'll probs want to log who approved this quote
|
||||||
|
Quote::create([
|
||||||
|
'quote' => $this->quote,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reject(): void
|
||||||
|
{
|
||||||
|
// TODO: we'll probs want to log who reject this quote
|
||||||
|
|
||||||
|
$this->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,16 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
|
||||||
|
|
||||||
class RequestedQuotes extends Model
|
|
||||||
{
|
|
||||||
use SoftDeletes;
|
|
||||||
|
|
||||||
protected $fillable = [
|
|
||||||
'quote',
|
|
||||||
'user_id',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
20
app/Policies/RequestQuotePolicy.php
Normal file
20
app/Policies/RequestQuotePolicy.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Policies;
|
||||||
|
|
||||||
|
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||||
|
|
||||||
|
class RequestQuotePolicy
|
||||||
|
{
|
||||||
|
use HandlesAuthorization;
|
||||||
|
|
||||||
|
public function approve(): bool
|
||||||
|
{
|
||||||
|
return auth()->user()->is_admin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reject(): bool
|
||||||
|
{
|
||||||
|
return auth()->user()->is_admin;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,6 +3,8 @@
|
|||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
// use Illuminate\Support\Facades\Gate;
|
// use Illuminate\Support\Facades\Gate;
|
||||||
|
use App\Models\RequestedQuote;
|
||||||
|
use App\Policies\RequestQuotePolicy;
|
||||||
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
||||||
|
|
||||||
class AuthServiceProvider extends ServiceProvider
|
class AuthServiceProvider extends ServiceProvider
|
||||||
@ -13,6 +15,7 @@ class AuthServiceProvider extends ServiceProvider
|
|||||||
* @var array<class-string, class-string>
|
* @var array<class-string, class-string>
|
||||||
*/
|
*/
|
||||||
protected $policies = [
|
protected $policies = [
|
||||||
|
RequestedQuote::class => RequestQuotePolicy::class,
|
||||||
//
|
//
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
<button {{ $attributes->merge(['type' => 'submit', 'class' => 'inline-flex items-center px-4 py-2 bg-nexi-red border border-transparent rounded-md font-bold text-xs text-white tracking-widest focus:bg-nexi-red active:bg-nexi-green focus:outline-none focus:ring-2 focus:ring-nexi-red focus:ring-offset-2 transition ease-in-out duration-150']) }}>
|
<button {{ $attributes->merge(['type' => 'submit', 'class' => 'inline-flex items-center justify-center px-4 py-2 bg-nexi-red border border-transparent rounded-md font-bold text-xs text-white tracking-widest focus:bg-nexi-red active:bg-nexi-green focus:outline-none focus:ring-2 focus:ring-nexi-red focus:ring-offset-2 transition ease-in-out duration-150']) }}>
|
||||||
{{ $slot }}
|
{{ $slot }}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@ -24,7 +24,7 @@
|
|||||||
<body class="antialiased bg-nexi-primary dark:bg-nexi-primary-dark font-sans text-nexi-black transition-colors duration-300">
|
<body class="antialiased bg-nexi-primary dark:bg-nexi-primary-dark font-sans text-nexi-black transition-colors duration-300">
|
||||||
<div class="min-h-screen flex flex-col sm:justify-center items-center pt-6 sm:pt-0 ">
|
<div class="min-h-screen flex flex-col sm:justify-center items-center pt-6 sm:pt-0 ">
|
||||||
{{-- TODO: REPLACE WITH OUR LOGO --}}
|
{{-- TODO: REPLACE WITH OUR LOGO --}}
|
||||||
<div class="mt-8">
|
<div class="mt-24">
|
||||||
<img class="h-24 w-auto rounded" src="https://benjamyn.love/PriceyBot.png" alt="">
|
<img class="h-24 w-auto rounded" src="https://benjamyn.love/PriceyBot.png" alt="">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
<div class="sm:fixed sm:top-0 sm:right-0 p-6 text-right z-10 bg-nexi-primary dark:bg-nexi-primary-dark transition-colors duration-300">
|
<div class="sm:fixed sm:top-0 flex flex-row-reverse w-full sm:right-0 p-6 text-right z-10 bg-nexi-primary dark:bg-nexi-primary-dark transition-colors duration-300">
|
||||||
@auth
|
@auth
|
||||||
<div class="pr-6 flex">
|
<div class="pr-6 flex">
|
||||||
<a href="{{ url('/dashboard') }}"
|
<a href="{{ url('/dashboard') }}"
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
use App\Models\Quote;
|
use App\Models\Quote;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use Livewire\Attributes\Layout;
|
use Livewire\Attributes\Layout;
|
||||||
|
use Livewire\Attributes\On;
|
||||||
use Livewire\Volt\Component;
|
use Livewire\Volt\Component;
|
||||||
|
|
||||||
new #[Layout('layouts.guest')] class extends Component
|
new #[Layout('layouts.guest')] class extends Component
|
||||||
@ -10,12 +11,18 @@ new #[Layout('layouts.guest')] class extends Component
|
|||||||
public Collection $quotes;
|
public Collection $quotes;
|
||||||
|
|
||||||
public function mount(): void
|
public function mount(): void
|
||||||
|
{
|
||||||
|
$this->getQuotes();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[On('quote-approved')]
|
||||||
|
public function getQuotes(): void
|
||||||
{
|
{
|
||||||
$this->quotes = Quote::all()->whereNull('deleted_at')->sortDesc();
|
$this->quotes = Quote::all()->whereNull('deleted_at')->sortDesc();
|
||||||
|
|
||||||
}
|
}
|
||||||
}; ?>
|
}; ?>
|
||||||
|
|
||||||
|
|
||||||
<div class="px-4 sm:px-6 lg:px-8">
|
<div class="px-4 sm:px-6 lg:px-8">
|
||||||
<div class="-mx-4 mt-10 ring-1 ring-gray-300 sm:mx-0 sm:rounded-lg bg-nexi-primary dark:bg-zinc-800 transition-colors duration-300">
|
<div class="-mx-4 mt-10 ring-1 ring-gray-300 sm:mx-0 sm:rounded-lg bg-nexi-primary dark:bg-zinc-800 transition-colors duration-300">
|
||||||
<table class="min-w-full divide-y divide-gray-300">
|
<table class="min-w-full divide-y divide-gray-300">
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Models\Quote;
|
use App\Models\Quote;
|
||||||
use App\Models\RequestedQuotes;
|
use App\Models\RequestedQuote;
|
||||||
use Livewire\Attributes\Layout;
|
use Livewire\Attributes\Layout;
|
||||||
use Livewire\Attributes\Rule;
|
use Livewire\Attributes\Rule;
|
||||||
use Livewire\Volt\Component;
|
use Livewire\Volt\Component;
|
||||||
@ -15,7 +15,7 @@ new #[Layout('layouts.guest')] class extends Component
|
|||||||
{
|
{
|
||||||
$validated = $this->validate();
|
$validated = $this->validate();
|
||||||
|
|
||||||
RequestedQuotes::create([
|
RequestedQuote::create([
|
||||||
'quote' => $validated['quote'],
|
'quote' => $validated['quote'],
|
||||||
'user_id' => auth()->user()->id ?? null,
|
'user_id' => auth()->user()->id ?? null,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Models\Quote;
|
use App\Models\Quote;
|
||||||
use App\Models\RequestedQuotes;
|
use App\Models\RequestedQuote;
|
||||||
use App\Providers\RouteServiceProvider;
|
use App\Providers\RouteServiceProvider;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
@ -17,17 +17,35 @@ new #[Layout('layouts.guest')] class extends Component
|
|||||||
public function mount(): void
|
public function mount(): void
|
||||||
{
|
{
|
||||||
$this->getRequestedQuotes();
|
$this->getRequestedQuotes();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[On('quote-requested')]
|
public function approve(RequestedQuote $quote): void
|
||||||
public function getRequestedQuotes()
|
|
||||||
{
|
{
|
||||||
$this->quotes = RequestedQuotes::all()->whereNull('deleted_at')->sortDesc();
|
$this->authorize('approve', $quote);
|
||||||
|
|
||||||
|
$quote->approve();
|
||||||
|
|
||||||
|
$this->dispatch('quote-approved');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reject(RequestedQuote $quote): void
|
||||||
|
{
|
||||||
|
$this->authorize('reject', $quote);
|
||||||
|
|
||||||
|
$quote->reject();
|
||||||
|
|
||||||
|
$this->dispatch('quote-rejected');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[On('quote-approved')]
|
||||||
|
#[On('quote-rejected')]
|
||||||
|
#[On('quote-requested')]
|
||||||
|
public function getRequestedQuotes(): void
|
||||||
|
{
|
||||||
|
$this->quotes = RequestedQuote::all()->whereNull('deleted_at')->sortDesc();
|
||||||
}
|
}
|
||||||
}; ?>
|
}; ?>
|
||||||
|
|
||||||
|
|
||||||
<div class="px-4 sm:px-6 lg:px-8">
|
<div class="px-4 sm:px-6 lg:px-8">
|
||||||
<div class="-mx-4 mt-10 ring-1 ring-gray-300 sm:mx-0 sm:rounded-lg bg-nexi-primary dark:bg-zinc-800 transition-colors duration-300">
|
<div class="-mx-4 mt-10 ring-1 ring-gray-300 sm:mx-0 sm:rounded-lg bg-nexi-primary dark:bg-zinc-800 transition-colors duration-300">
|
||||||
<table class="min-w-full divide-y divide-gray-300">
|
<table class="min-w-full divide-y divide-gray-300">
|
||||||
@ -37,7 +55,9 @@ new #[Layout('layouts.guest')] class extends Component
|
|||||||
class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-nexi-black dark:text-gray-200 sm:pl-6">
|
class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-nexi-black dark:text-gray-200 sm:pl-6">
|
||||||
Requested Quotes
|
Requested Quotes
|
||||||
</th>
|
</th>
|
||||||
{{-- TODO: add logged in user stuff --}}
|
@if(auth()->user()->is_admin)
|
||||||
|
<th scope="col"></th>
|
||||||
|
@endif
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -46,6 +66,18 @@ new #[Layout('layouts.guest')] class extends Component
|
|||||||
<td class="relative py-4 pl-4 pr-3 text-sm sm:pl-6 border-t text-nexi-black dark:text-gray-200">
|
<td class="relative py-4 pl-4 pr-3 text-sm sm:pl-6 border-t text-nexi-black dark:text-gray-200">
|
||||||
{{ $quote->quote }}
|
{{ $quote->quote }}
|
||||||
</td>
|
</td>
|
||||||
|
@if(auth()->user()->is_admin)
|
||||||
|
<td class="relative w-8 pl-4 pr-3 text-sm sm:pl-6 border-t">
|
||||||
|
<div class="flex flex-row space-x-2">
|
||||||
|
<form wire:submit="approve({{ $quote }})">
|
||||||
|
<x-primary-button class="bg-nexi-green w-24">{{ __('Approve') }}</x-primary-button>
|
||||||
|
</form>
|
||||||
|
<form wire:submit="reject({{ $quote }})">
|
||||||
|
<x-primary-button class="bg-nexi-red w-24">{{ __('Reject') }}</x-primary-button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
@endif
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
Reference in New Issue
Block a user