refactor: implement verification action concerns and enhance admin verification page functionality
This commit is contained in:
parent
2d2ef77a94
commit
e5cbbe7e96
@ -3,13 +3,13 @@
|
|||||||
namespace App\Filament\Pages\AdminVerification\Actions;
|
namespace App\Filament\Pages\AdminVerification\Actions;
|
||||||
|
|
||||||
use App\Enums\DecisionAdmin;
|
use App\Enums\DecisionAdmin;
|
||||||
use App\Filament\Pages\AdminVerification\Actions\Concerns\CanProcessReview;
|
use App\Filament\Pages\AdminVerification\Concerns\CanProcessVerificationReview;
|
||||||
use App\Filament\Support\CheerfulNotification;
|
use App\Filament\Support\CheerfulNotification;
|
||||||
use Filament\Actions\Action;
|
use Filament\Actions\Action;
|
||||||
|
|
||||||
class ApproveAction extends Action
|
class ApproveAction extends Action
|
||||||
{
|
{
|
||||||
use CanProcessReview;
|
use CanProcessVerificationReview;
|
||||||
|
|
||||||
public static function getDefaultName(): ?string
|
public static function getDefaultName(): ?string
|
||||||
{
|
{
|
||||||
@ -21,9 +21,11 @@ protected function setUp(): void
|
|||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
$this->label('Setujui')
|
$this->label('Setujui')
|
||||||
|
->authorize(fn (): bool => auth()->user()?->can('Approve:AdminVerification'))
|
||||||
->color('success')
|
->color('success')
|
||||||
->icon('heroicon-o-check')
|
->icon('heroicon-o-check')
|
||||||
->size('sm')
|
->size('sm')
|
||||||
|
->link()
|
||||||
->requiresConfirmation()
|
->requiresConfirmation()
|
||||||
->modalHeading(fn () => CheerfulNotification::getByKey('actions.approve.title'))
|
->modalHeading(fn () => CheerfulNotification::getByKey('actions.approve.title'))
|
||||||
->modalDescription(fn () => CheerfulNotification::getByKey('actions.approve.description'))
|
->modalDescription(fn () => CheerfulNotification::getByKey('actions.approve.description'))
|
||||||
|
|||||||
@ -3,14 +3,14 @@
|
|||||||
namespace App\Filament\Pages\AdminVerification\Actions;
|
namespace App\Filament\Pages\AdminVerification\Actions;
|
||||||
|
|
||||||
use App\Enums\DecisionAdmin;
|
use App\Enums\DecisionAdmin;
|
||||||
use App\Filament\Pages\AdminVerification\Actions\Concerns\CanProcessReview;
|
use App\Filament\Pages\AdminVerification\Concerns\CanProcessVerificationReview;
|
||||||
use App\Filament\Support\CheerfulNotification;
|
use App\Filament\Support\CheerfulNotification;
|
||||||
use Filament\Actions\Action;
|
use Filament\Actions\Action;
|
||||||
use Filament\Forms\Components\Textarea;
|
use Filament\Forms\Components\Textarea;
|
||||||
|
|
||||||
class RejectAction extends Action
|
class RejectAction extends Action
|
||||||
{
|
{
|
||||||
use CanProcessReview;
|
use CanProcessVerificationReview;
|
||||||
|
|
||||||
public static function getDefaultName(): ?string
|
public static function getDefaultName(): ?string
|
||||||
{
|
{
|
||||||
@ -22,9 +22,11 @@ protected function setUp(): void
|
|||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
$this->label('Tolak')
|
$this->label('Tolak')
|
||||||
|
->authorize(fn (): bool => auth()->user()?->can('Reject:AdminVerification'))
|
||||||
->color('danger')
|
->color('danger')
|
||||||
->icon('heroicon-o-x-mark')
|
->icon('heroicon-o-x-mark')
|
||||||
->size('sm')
|
->size('sm')
|
||||||
|
->link()
|
||||||
->requiresConfirmation()
|
->requiresConfirmation()
|
||||||
->modalHeading(fn () => CheerfulNotification::getByKey('actions.reject.title'))
|
->modalHeading(fn () => CheerfulNotification::getByKey('actions.reject.title'))
|
||||||
->modalDescription(fn () => CheerfulNotification::getByKey('actions.reject.description'))
|
->modalDescription(fn () => CheerfulNotification::getByKey('actions.reject.description'))
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
namespace App\Filament\Pages\AdminVerification\Actions;
|
namespace App\Filament\Pages\AdminVerification\Actions;
|
||||||
|
|
||||||
use App\Enums\DecisionAdmin;
|
use App\Enums\DecisionAdmin;
|
||||||
use App\Filament\Pages\AdminVerification\Actions\Concerns\CanProcessReview;
|
use App\Filament\Pages\AdminVerification\Concerns\CanProcessVerificationReview;
|
||||||
use App\Filament\Support\CheerfulNotification;
|
use App\Filament\Support\CheerfulNotification;
|
||||||
use Filament\Actions\Action;
|
use Filament\Actions\Action;
|
||||||
use Filament\Forms\Components\Textarea;
|
use Filament\Forms\Components\Textarea;
|
||||||
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
class RevisionAction extends Action
|
class RevisionAction extends Action
|
||||||
{
|
{
|
||||||
use CanProcessReview;
|
use CanProcessVerificationReview;
|
||||||
|
|
||||||
public static function getDefaultName(): ?string
|
public static function getDefaultName(): ?string
|
||||||
{
|
{
|
||||||
@ -23,9 +23,11 @@ protected function setUp(): void
|
|||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
$this->label('Minta Revisi')
|
$this->label('Minta Revisi')
|
||||||
|
->authorize(fn (): bool => auth()->user()?->can('Revision:AdminVerification'))
|
||||||
->color('warning')
|
->color('warning')
|
||||||
->icon('heroicon-o-pencil-square')
|
->icon('heroicon-o-pencil-square')
|
||||||
->size('sm')
|
->size('sm')
|
||||||
|
->link()
|
||||||
->modalHeading(fn () => CheerfulNotification::getByKey('actions.revision.title'))
|
->modalHeading(fn () => CheerfulNotification::getByKey('actions.revision.title'))
|
||||||
->modalDescription(fn () => CheerfulNotification::getByKey('actions.revision.description'))
|
->modalDescription(fn () => CheerfulNotification::getByKey('actions.revision.description'))
|
||||||
->schema([
|
->schema([
|
||||||
|
|||||||
29
app/Filament/Pages/AdminVerification/Actions/ViewAction.php
Normal file
29
app/Filament/Pages/AdminVerification/Actions/ViewAction.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Pages\AdminVerification\Actions;
|
||||||
|
|
||||||
|
use App\Filament\Pages\AdminVerification\Concerns\CanProcessVerificationReview;
|
||||||
|
use App\Filament\Resources\Manage\Partners\Pages\ViewPartner;
|
||||||
|
use Filament\Actions\Action;
|
||||||
|
|
||||||
|
class ViewAction extends Action
|
||||||
|
{
|
||||||
|
use CanProcessVerificationReview;
|
||||||
|
|
||||||
|
public static function getDefaultName(): ?string
|
||||||
|
{
|
||||||
|
return 'view';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->label('Lihat')
|
||||||
|
->color('success')
|
||||||
|
->icon('heroicon-o-eye')
|
||||||
|
->size('sm')
|
||||||
|
->link()
|
||||||
|
->url(fn (array $arguments) => ViewPartner::getUrl(['record' => $arguments['id']]));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Filament\Pages\AdminVerification\Actions\Concerns;
|
namespace App\Filament\Pages\AdminVerification\Concerns;
|
||||||
|
|
||||||
use App\Enums\DecisionAdmin;
|
use App\Enums\DecisionAdmin;
|
||||||
use App\Enums\VerificationStatus;
|
use App\Enums\VerificationStatus;
|
||||||
@ -13,25 +13,14 @@
|
|||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
trait CanProcessReview
|
trait CanProcessVerificationReview
|
||||||
{
|
{
|
||||||
protected function processReview(int $requestId, DecisionAdmin $decision, ?string $note): void
|
protected function processReview(int $requestId, DecisionAdmin $decision, ?string $note): void
|
||||||
{
|
{
|
||||||
$verificationRequest = VerificationRequest::with(['company.partnerMedia.journalists'])->find($requestId);
|
$verificationRequest = VerificationRequest::with(['company.partnerMedia.journalists'])->findOrFail($requestId);
|
||||||
|
|
||||||
if (! $verificationRequest) {
|
|
||||||
CheerfulNotification::danger(
|
|
||||||
CheerfulNotification::getByKey('verification.admin.process.not_found.title'),
|
|
||||||
CheerfulNotification::getByKey('verification.admin.process.not_found.body')
|
|
||||||
)
|
|
||||||
->send();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DB::beginTransaction();
|
DB::transaction(function () use ($verificationRequest, $decision, $note) {
|
||||||
|
|
||||||
// Create review record
|
// Create review record
|
||||||
VerificationReview::create([
|
VerificationReview::create([
|
||||||
'verification_request_id' => $verificationRequest->id,
|
'verification_request_id' => $verificationRequest->id,
|
||||||
@ -50,8 +39,7 @@ protected function processReview(int $requestId, DecisionAdmin $decision, ?strin
|
|||||||
$verificationRequest->update([
|
$verificationRequest->update([
|
||||||
'status' => $newStatus,
|
'status' => $newStatus,
|
||||||
]);
|
]);
|
||||||
|
});
|
||||||
DB::commit();
|
|
||||||
|
|
||||||
$actionLabel = match ($decision) {
|
$actionLabel = match ($decision) {
|
||||||
DecisionAdmin::APPROVED => 'disetujui',
|
DecisionAdmin::APPROVED => 'disetujui',
|
||||||
@ -95,7 +83,6 @@ protected function processReview(int $requestId, DecisionAdmin $decision, ?strin
|
|||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
DB::rollBack();
|
|
||||||
Log::error('Verification processing failed', [
|
Log::error('Verification processing failed', [
|
||||||
'error' => $e->getMessage(),
|
'error' => $e->getMessage(),
|
||||||
'trace' => $e->getTraceAsString(),
|
'trace' => $e->getTraceAsString(),
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Pages\AdminVerification\Concerns;
|
||||||
|
|
||||||
|
use App\Filament\Pages\AdminVerification\Actions\ApproveAction;
|
||||||
|
use App\Filament\Pages\AdminVerification\Actions\RejectAction;
|
||||||
|
use App\Filament\Pages\AdminVerification\Actions\RevisionAction;
|
||||||
|
use App\Filament\Pages\AdminVerification\Actions\ViewAction;
|
||||||
|
use Filament\Actions\Action;
|
||||||
|
|
||||||
|
trait HasVerificationActions
|
||||||
|
{
|
||||||
|
public function approveAction(): Action
|
||||||
|
{
|
||||||
|
return ApproveAction::make();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function revisionAction(): Action
|
||||||
|
{
|
||||||
|
return RevisionAction::make();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rejectAction(): Action
|
||||||
|
{
|
||||||
|
return RejectAction::make();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function viewAction(): Action
|
||||||
|
{
|
||||||
|
return ViewAction::make();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Pages\AdminVerification\Concerns;
|
||||||
|
|
||||||
|
use App\Enums\VerificationStatus;
|
||||||
|
use App\Models\VerificationRequest;
|
||||||
|
use Livewire\Attributes\Computed;
|
||||||
|
|
||||||
|
trait HasVerificationFilters
|
||||||
|
{
|
||||||
|
public string $filterStatus = '1';
|
||||||
|
|
||||||
|
public int $rowsToDisplay = 12;
|
||||||
|
|
||||||
|
public function loadMore(): void
|
||||||
|
{
|
||||||
|
$this->rowsToDisplay += 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFilter(string $status): void
|
||||||
|
{
|
||||||
|
$this->filterStatus = $status;
|
||||||
|
$this->rowsToDisplay = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Computed]
|
||||||
|
public function getFilters(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
'id' => 'all',
|
||||||
|
'label' => 'Semua',
|
||||||
|
'icon' => 'heroicon-s-squares-2x2',
|
||||||
|
'color' => 'primary',
|
||||||
|
'count' => VerificationRequest::count(),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => (string) VerificationStatus::PENDING->value,
|
||||||
|
'label' => 'Menunggu',
|
||||||
|
'icon' => 'heroicon-s-clock',
|
||||||
|
'color' => 'warning',
|
||||||
|
'count' => VerificationRequest::query()->pending()->count(),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => (string) VerificationStatus::NEED_REVISION->value,
|
||||||
|
'label' => 'Revisi',
|
||||||
|
'icon' => 'heroicon-s-pencil-square',
|
||||||
|
'color' => 'info',
|
||||||
|
'count' => VerificationRequest::query()->needRevision()->count(),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => (string) VerificationStatus::APPROVED->value,
|
||||||
|
'label' => 'Disetujui',
|
||||||
|
'icon' => 'heroicon-s-check-circle',
|
||||||
|
'color' => 'success',
|
||||||
|
'count' => VerificationRequest::query()->approved()->count(),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => (string) VerificationStatus::REJECTED->value,
|
||||||
|
'label' => 'Ditolak',
|
||||||
|
'icon' => 'heroicon-s-x-circle',
|
||||||
|
'color' => 'danger',
|
||||||
|
'count' => VerificationRequest::query()->rejected()->count(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Pages\AdminVerification\Concerns;
|
||||||
|
|
||||||
|
use App\Filament\Support\CheerfulNotification;
|
||||||
|
|
||||||
|
trait HasVerificationNotifications
|
||||||
|
{
|
||||||
|
public function getEmptyStateHeading(): string
|
||||||
|
{
|
||||||
|
return CheerfulNotification::getByKey('verification.admin.empty_state.heading');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEmptyStateDescription(): string
|
||||||
|
{
|
||||||
|
return CheerfulNotification::getByKey('verification.admin.empty_state.description');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,15 +3,14 @@
|
|||||||
namespace App\Filament\Pages\AdminVerification;
|
namespace App\Filament\Pages\AdminVerification;
|
||||||
|
|
||||||
use App\Enums\VerificationStatus;
|
use App\Enums\VerificationStatus;
|
||||||
use App\Filament\Pages\AdminVerification\Actions\ApproveAction;
|
use App\Filament\Pages\AdminVerification\Concerns\HasVerificationActions;
|
||||||
use App\Filament\Pages\AdminVerification\Actions\RejectAction;
|
use App\Filament\Pages\AdminVerification\Concerns\HasVerificationFilters;
|
||||||
use App\Filament\Pages\AdminVerification\Actions\RevisionAction;
|
use App\Filament\Pages\AdminVerification\Concerns\HasVerificationNotifications;
|
||||||
use App\Filament\Resources\Manage\Partners\Pages\ViewPartner;
|
use App\Filament\Resources\Manage\Partners\Pages\ViewPartner;
|
||||||
use App\Filament\Support\CheerfulNotification;
|
use App\Filament\Support\CheerfulNotification;
|
||||||
use App\Models\VerificationRequest;
|
use App\Models\VerificationRequest;
|
||||||
use BackedEnum;
|
use BackedEnum;
|
||||||
use BezhanSalleh\FilamentShield\Traits\HasPageShield;
|
use BezhanSalleh\FilamentShield\Traits\HasPageShield;
|
||||||
use Filament\Actions\Action;
|
|
||||||
use Filament\Actions\Concerns\InteractsWithActions;
|
use Filament\Actions\Concerns\InteractsWithActions;
|
||||||
use Filament\Actions\Contracts\HasActions;
|
use Filament\Actions\Contracts\HasActions;
|
||||||
use Filament\Forms\Concerns\InteractsWithForms;
|
use Filament\Forms\Concerns\InteractsWithForms;
|
||||||
@ -24,11 +23,7 @@
|
|||||||
|
|
||||||
class Index extends Page implements HasActions, HasForms
|
class Index extends Page implements HasActions, HasForms
|
||||||
{
|
{
|
||||||
use HasPageShield, InteractsWithActions, InteractsWithForms;
|
use HasPageShield, HasVerificationActions, HasVerificationFilters, HasVerificationNotifications, InteractsWithActions, InteractsWithForms;
|
||||||
|
|
||||||
public string $filterStatus = '1';
|
|
||||||
|
|
||||||
public int $rowsToDisplay = 12;
|
|
||||||
|
|
||||||
protected static string|UnitEnum|null $navigationGroup = 'Kelola';
|
protected static string|UnitEnum|null $navigationGroup = 'Kelola';
|
||||||
|
|
||||||
@ -44,7 +39,7 @@ class Index extends Page implements HasActions, HasForms
|
|||||||
|
|
||||||
protected string $view = 'filament.pages.admin-verification';
|
protected string $view = 'filament.pages.admin-verification';
|
||||||
|
|
||||||
public static function canAccess(array $parameters = []): bool
|
public static function canAccess(): bool
|
||||||
{
|
{
|
||||||
return auth()->user()->can('View:AdminVerification');
|
return auth()->user()->can('View:AdminVerification');
|
||||||
}
|
}
|
||||||
@ -157,6 +152,7 @@ public function verifications(): LengthAwarePaginator
|
|||||||
'createdAt' => $review->created_at->translatedFormat('l, d M Y H:i'),
|
'createdAt' => $review->created_at->translatedFormat('l, d M Y H:i'),
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
|
|
||||||
'messages' => [
|
'messages' => [
|
||||||
'detail' => CheerfulNotification::getByKey('verification.admin.messages.detail'),
|
'detail' => CheerfulNotification::getByKey('verification.admin.messages.detail'),
|
||||||
'revision' => CheerfulNotification::getByKey('verification.admin.messages.revision'),
|
'revision' => CheerfulNotification::getByKey('verification.admin.messages.revision'),
|
||||||
@ -166,91 +162,4 @@ public function verifications(): LengthAwarePaginator
|
|||||||
];
|
];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadMore(): void
|
|
||||||
{
|
|
||||||
$this->rowsToDisplay += 12;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setFilter(string $status): void
|
|
||||||
{
|
|
||||||
$this->filterStatus = $status;
|
|
||||||
$this->rowsToDisplay = 12;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Computed]
|
|
||||||
public function getFilters(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
[
|
|
||||||
'id' => 'all',
|
|
||||||
'label' => 'Semua',
|
|
||||||
'icon' => 'heroicon-s-squares-2x2',
|
|
||||||
'color' => 'primary',
|
|
||||||
'count' => VerificationRequest::count(),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => (string) VerificationStatus::PENDING->value,
|
|
||||||
'label' => 'Menunggu',
|
|
||||||
'icon' => 'heroicon-s-clock',
|
|
||||||
'color' => 'warning',
|
|
||||||
'count' => VerificationRequest::pending()->count(),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => (string) VerificationStatus::NEED_REVISION->value,
|
|
||||||
'label' => 'Revisi',
|
|
||||||
'icon' => 'heroicon-s-pencil-square',
|
|
||||||
'color' => 'info',
|
|
||||||
'count' => VerificationRequest::needRevision()->count(),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => (string) VerificationStatus::APPROVED->value,
|
|
||||||
'label' => 'Disetujui',
|
|
||||||
'icon' => 'heroicon-s-check-circle',
|
|
||||||
'color' => 'success',
|
|
||||||
'count' => VerificationRequest::approved()->count(),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => (string) VerificationStatus::REJECTED->value,
|
|
||||||
'label' => 'Ditolak',
|
|
||||||
'icon' => 'heroicon-s-x-circle',
|
|
||||||
'color' => 'danger',
|
|
||||||
'count' => VerificationRequest::rejected()->count(),
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Approve verification action
|
|
||||||
*/
|
|
||||||
public function approveAction(): Action
|
|
||||||
{
|
|
||||||
return ApproveAction::make();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Revision verification action
|
|
||||||
*/
|
|
||||||
public function revisionAction(): Action
|
|
||||||
{
|
|
||||||
return RevisionAction::make();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reject verification action
|
|
||||||
*/
|
|
||||||
public function rejectAction(): Action
|
|
||||||
{
|
|
||||||
return RejectAction::make();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getEmptyStateHeading(): string
|
|
||||||
{
|
|
||||||
return CheerfulNotification::getByKey('verification.admin.empty_state.heading');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getEmptyStateDescription(): string
|
|
||||||
{
|
|
||||||
return CheerfulNotification::getByKey('verification.admin.empty_state.description');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,9 @@ public function run(): void
|
|||||||
"View:Analytic",
|
"View:Analytic",
|
||||||
|
|
||||||
"View:AdminVerification",
|
"View:AdminVerification",
|
||||||
|
"Approve:AdminVerification",
|
||||||
|
"Reject:AdminVerification",
|
||||||
|
"Revision:AdminVerification",
|
||||||
|
|
||||||
"ViewAny:Announcement",
|
"ViewAny:Announcement",
|
||||||
"View:Announcement",
|
"View:Announcement",
|
||||||
@ -281,6 +284,9 @@ public function run(): void
|
|||||||
"View:Analytic",
|
"View:Analytic",
|
||||||
|
|
||||||
"View:AdminVerification",
|
"View:AdminVerification",
|
||||||
|
"Approve:AdminVerification",
|
||||||
|
"Reject:AdminVerification",
|
||||||
|
"Revision:AdminVerification",
|
||||||
|
|
||||||
"ViewAny:Announcement",
|
"ViewAny:Announcement",
|
||||||
"View:Announcement",
|
"View:Announcement",
|
||||||
|
|||||||
@ -265,16 +265,6 @@
|
|||||||
],
|
],
|
||||||
'admin' => [
|
'admin' => [
|
||||||
'process' => [
|
'process' => [
|
||||||
'not_found' => [
|
|
||||||
'title' => [
|
|
||||||
'cheerful' => 'Belum ketemu nih 🙌',
|
|
||||||
'formal' => 'Data Tidak Ditemukan',
|
|
||||||
],
|
|
||||||
'body' => [
|
|
||||||
'cheerful' => 'Data verifikasi belum kami temukan. Coba sebentar lagi, ya.',
|
|
||||||
'formal' => 'Permintaan verifikasi tidak ditemukan dalam sistem kami.',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'success' => [
|
'success' => [
|
||||||
'title' => [
|
'title' => [
|
||||||
'cheerful' => 'Berhasil Diproses! ✨',
|
'cheerful' => 'Berhasil Diproses! ✨',
|
||||||
|
|||||||
@ -1,24 +1,31 @@
|
|||||||
<x-filament-panels::page>
|
<x-filament-panels::page>
|
||||||
<div class="flex flex-wrap items-center gap-3">
|
<div class="flex flex-wrap items-center gap-3">
|
||||||
@foreach ($this->getFilters as $filter)
|
@foreach ($this->getFilters as $filter)
|
||||||
<button wire:click="setFilter('{{ $filter['id'] }}')"
|
<x-filament::button wire:click="setFilter('{{ $filter['id'] }}')" @class([
|
||||||
@class([
|
|
||||||
'group inline-flex items-center gap-2.5 px-5 py-2.5 text-sm font-bold custom-rounded transition-all duration-300 active:scale-95 shadow-sm hover:shadow-md',
|
'group inline-flex items-center gap-2.5 px-5 py-2.5 text-sm font-bold custom-rounded transition-all duration-300 active:scale-95 shadow-sm hover:shadow-md',
|
||||||
// Active Styles
|
// Active Styles
|
||||||
$filterStatus === $filter['id'] ? match($filter['color']) {
|
$filterStatus === $filter['id']
|
||||||
'primary' => 'bg-primary-500 text-white shadow-primary-500/30 ring-2 ring-primary-500/20',
|
? match ($filter['color']) {
|
||||||
'warning' => 'bg-warning-500 text-white shadow-warning-500/30 ring-2 ring-warning-500/20',
|
'primary'
|
||||||
'success' => 'bg-success-500 text-white shadow-success-500/30 ring-2 ring-success-500/20',
|
=> 'bg-primary-500 text-white shadow-primary-500/30 ring-2 ring-primary-500/20',
|
||||||
'danger' => 'bg-danger-500 text-white shadow-danger-500/30 ring-2 ring-danger-500/20',
|
'warning'
|
||||||
'info' => 'bg-info-500 text-white shadow-info-500/30 ring-2 ring-info-500/20',
|
=> 'bg-warning-500 text-white shadow-warning-500/30 ring-2 ring-warning-500/20',
|
||||||
|
'success'
|
||||||
|
=> 'bg-success-500 text-white shadow-success-500/30 ring-2 ring-success-500/20',
|
||||||
|
'danger'
|
||||||
|
=> 'bg-danger-500 text-white shadow-danger-500/30 ring-2 ring-danger-500/20',
|
||||||
|
'info'
|
||||||
|
=> 'bg-info-500 text-white shadow-info-500/30 ring-2 ring-info-500/20',
|
||||||
default => 'bg-gray-500 text-white shadow-gray-500/25',
|
default => 'bg-gray-500 text-white shadow-gray-500/25',
|
||||||
} : 'bg-white dark:bg-gray-900 text-gray-600 dark:text-gray-400 border border-gray-200 dark:border-gray-800 hover:border-gray-300 dark:hover:border-gray-700',
|
}
|
||||||
|
: 'bg-white dark:bg-gray-900 text-gray-600 dark:text-gray-400 border border-gray-200 dark:border-gray-800 hover:border-gray-300 dark:hover:border-gray-700',
|
||||||
])>
|
])>
|
||||||
@if ($filter['icon'])
|
@if ($filter['icon'])
|
||||||
<x-dynamic-component :component="$filter['icon']"
|
<x-dynamic-component :component="$filter['icon']" @class([
|
||||||
@class([
|
|
||||||
'w-5 h-5 transition-transform duration-300 group-hover:scale-110',
|
'w-5 h-5 transition-transform duration-300 group-hover:scale-110',
|
||||||
$filterStatus === $filter['id'] ? 'text-white' : match($filter['color']) {
|
$filterStatus === $filter['id']
|
||||||
|
? 'text-white'
|
||||||
|
: match ($filter['color']) {
|
||||||
'primary' => 'text-primary-500',
|
'primary' => 'text-primary-500',
|
||||||
'warning' => 'text-warning-500',
|
'warning' => 'text-warning-500',
|
||||||
'success' => 'text-success-500',
|
'success' => 'text-success-500',
|
||||||
@ -26,29 +33,37 @@
|
|||||||
'info' => 'text-info-500',
|
'info' => 'text-info-500',
|
||||||
default => 'text-gray-500',
|
default => 'text-gray-500',
|
||||||
},
|
},
|
||||||
])
|
]) />
|
||||||
/>
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<span>{{ $filter['label'] }}</span>
|
<span>{{ $filter['label'] }}</span>
|
||||||
|
|
||||||
<span @class([
|
<span @class([
|
||||||
'px-2.5 py-0.5 text-[10px] font-extrabold rounded-full transition-all duration-300',
|
'px-2.5 py-0.5 text-[10px] font-extrabold rounded-full transition-all duration-300',
|
||||||
$filterStatus === $filter['id'] ? 'bg-white/20 text-white shadow-inner' : match($filter['color']) {
|
$filterStatus === $filter['id']
|
||||||
'primary' => 'bg-primary-100 text-primary-700 dark:bg-primary-500/20 dark:text-primary-400',
|
? 'bg-white/20 text-white shadow-inner'
|
||||||
'warning' => 'bg-warning-100 text-warning-700 dark:bg-warning-500/20 dark:text-warning-300',
|
: match ($filter['color']) {
|
||||||
'success' => 'bg-success-100 text-success-700 dark:bg-success-500/20 dark:text-success-400',
|
'primary'
|
||||||
'danger' => 'bg-danger-100 text-danger-700 dark:bg-danger-500/20 dark:text-danger-400',
|
=> 'bg-primary-100 text-primary-700 dark:bg-primary-500/20 dark:text-primary-400',
|
||||||
'info' => 'bg-info-100 text-info-700 dark:bg-info-500/20 dark:text-info-400',
|
'warning'
|
||||||
default => 'bg-gray-100 text-gray-700 dark:bg-gray-500/20 dark:text-gray-400',
|
=> 'bg-warning-100 text-warning-700 dark:bg-warning-500/20 dark:text-warning-300',
|
||||||
|
'success'
|
||||||
|
=> 'bg-success-100 text-success-700 dark:bg-success-500/20 dark:text-success-400',
|
||||||
|
'danger'
|
||||||
|
=> 'bg-danger-100 text-danger-700 dark:bg-danger-500/20 dark:text-danger-400',
|
||||||
|
'info'
|
||||||
|
=> 'bg-info-100 text-info-700 dark:bg-info-500/20 dark:text-info-400',
|
||||||
|
default
|
||||||
|
=> 'bg-gray-100 text-gray-700 dark:bg-gray-500/20 dark:text-gray-400',
|
||||||
},
|
},
|
||||||
])>
|
])>
|
||||||
{{ $filter['count'] ?? 0 }}
|
{{ $filter['count'] ?? 0 }}
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</x-filament::button>
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<x-filament::section>
|
||||||
{{-- Verification Cards Grid --}}
|
{{-- Verification Cards Grid --}}
|
||||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||||
@forelse ($this->verifications as $verification)
|
@forelse ($this->verifications as $verification)
|
||||||
@ -79,7 +94,8 @@ class="w-10 h-10 rounded-full bg-primary-100 dark:bg-primary-500/20 flex items-c
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="min-w-0 flex-1">
|
<div class="min-w-0 flex-1">
|
||||||
<p class="text-xs text-gray-500 dark:text-gray-400 uppercase font-semibold">Diajukan oleh
|
<p class="text-xs text-gray-500 dark:text-gray-400 uppercase font-semibold">Diajukan
|
||||||
|
oleh
|
||||||
</p>
|
</p>
|
||||||
<p class="text-sm font-medium text-gray-900 dark:text-white truncate">
|
<p class="text-sm font-medium text-gray-900 dark:text-white truncate">
|
||||||
{{ $verification['submittedBy'] }}
|
{{ $verification['submittedBy'] }}
|
||||||
@ -88,12 +104,14 @@ class="w-10 h-10 rounded-full bg-primary-100 dark:bg-primary-500/20 flex items-c
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- Data Summary --}}
|
{{-- Data Summary --}}
|
||||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-3 p-3 bg-gray-50 dark:bg-gray-800 custom-rounded">
|
<div
|
||||||
|
class="grid grid-cols-1 md:grid-cols-3 gap-3 p-3 bg-gray-50 dark:bg-gray-800 custom-rounded">
|
||||||
{{-- Company Summary --}}
|
{{-- Company Summary --}}
|
||||||
<div>
|
<div>
|
||||||
<div class="flex items-center gap-2 mb-1">
|
<div class="flex items-center gap-2 mb-1">
|
||||||
<x-heroicon-o-building-office-2 class="w-4 h-4 text-primary-500" />
|
<x-heroicon-o-building-office-2 class="w-4 h-4 text-primary-500" />
|
||||||
<p class="text-xs font-semibold text-gray-600 dark:text-gray-400 uppercase">Perusahaan
|
<p class="text-xs font-semibold text-gray-600 dark:text-gray-400 uppercase">
|
||||||
|
Perusahaan
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-sm font-medium text-gray-900 dark:text-white truncate">
|
<p class="text-sm font-medium text-gray-900 dark:text-white truncate">
|
||||||
@ -108,7 +126,8 @@ class="w-10 h-10 rounded-full bg-primary-100 dark:bg-primary-500/20 flex items-c
|
|||||||
<div>
|
<div>
|
||||||
<div class="flex items-center gap-2 mb-1">
|
<div class="flex items-center gap-2 mb-1">
|
||||||
<x-heroicon-o-newspaper class="w-4 h-4 text-info-500" />
|
<x-heroicon-o-newspaper class="w-4 h-4 text-info-500" />
|
||||||
<p class="text-xs font-semibold text-gray-600 dark:text-gray-400 uppercase">Media</p>
|
<p class="text-xs font-semibold text-gray-600 dark:text-gray-400 uppercase">Media
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-sm font-medium text-gray-900 dark:text-white truncate">
|
<p class="text-sm font-medium text-gray-900 dark:text-white truncate">
|
||||||
{{ $verification['summary']['media']['name'] }}
|
{{ $verification['summary']['media']['name'] }}
|
||||||
@ -122,7 +141,8 @@ class="w-10 h-10 rounded-full bg-primary-100 dark:bg-primary-500/20 flex items-c
|
|||||||
<div>
|
<div>
|
||||||
<div class="flex items-center gap-2 mb-1">
|
<div class="flex items-center gap-2 mb-1">
|
||||||
<x-heroicon-o-identification class="w-4 h-4 text-info-500" />
|
<x-heroicon-o-identification class="w-4 h-4 text-info-500" />
|
||||||
<p class="text-xs font-semibold text-gray-600 dark:text-gray-400 uppercase">Jurnalis</p>
|
<p class="text-xs font-semibold text-gray-600 dark:text-gray-400 uppercase">Jurnalis
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-sm font-medium text-gray-900 dark:text-white">
|
<p class="text-sm font-medium text-gray-900 dark:text-white">
|
||||||
{{ $verification['summary']['journalists']['count'] }} jurnalis
|
{{ $verification['summary']['journalists']['count'] }} jurnalis
|
||||||
@ -225,18 +245,28 @@ class="w-4 h-4 text-gray-500 transition-transform duration-200"
|
|||||||
<x-slot name="footer">
|
<x-slot name="footer">
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
{{-- View Detail Button --}}
|
{{-- View Detail Button --}}
|
||||||
|
@can('View:AdminVerification')
|
||||||
@if ($verification['company']['detailUrl'])
|
@if ($verification['company']['detailUrl'])
|
||||||
<x-filament::button color="gray" size="sm" icon="heroicon-o-eye" tag="a"
|
{{ ($this->viewAction)(['id' => $verification['id']]) }}
|
||||||
:href="$verification['company']['detailUrl']">
|
|
||||||
{{ $verification['messages']['detail'] }}
|
|
||||||
</x-filament::button>
|
|
||||||
@endif
|
@endif
|
||||||
|
@endcan
|
||||||
|
|
||||||
{{-- Action Buttons based on status --}}
|
{{-- Action Buttons based on status --}}
|
||||||
@if ($verification['status']['isPending'])
|
@if ($verification['status']['isPending'])
|
||||||
|
@canAny(['Approve:AdminVerification', 'Revision:AdminVerification',
|
||||||
|
'Reject:AdminVerification'])
|
||||||
|
@can('Approve:AdminVerification')
|
||||||
{{ ($this->approveAction)(['id' => $verification['id']]) }}
|
{{ ($this->approveAction)(['id' => $verification['id']]) }}
|
||||||
|
@endcan
|
||||||
|
|
||||||
|
@can('Revision:AdminVerification')
|
||||||
{{ ($this->revisionAction)(['id' => $verification['id']]) }}
|
{{ ($this->revisionAction)(['id' => $verification['id']]) }}
|
||||||
|
@endcan
|
||||||
|
|
||||||
|
@can('Reject:AdminVerification')
|
||||||
{{ ($this->rejectAction)(['id' => $verification['id']]) }}
|
{{ ($this->rejectAction)(['id' => $verification['id']]) }}
|
||||||
|
@endcan
|
||||||
|
@endcanAny
|
||||||
@elseif($verification['status']['isRevision'])
|
@elseif($verification['status']['isRevision'])
|
||||||
<span
|
<span
|
||||||
class="flex items-center gap-1 text-xs text-warning-600 dark:text-warning-400 font-medium italic">
|
class="flex items-center gap-1 text-xs text-warning-600 dark:text-warning-400 font-medium italic">
|
||||||
@ -261,10 +291,7 @@ class="flex items-center gap-1 text-xs text-danger-600 dark:text-danger-400 font
|
|||||||
</x-filament::section>
|
</x-filament::section>
|
||||||
@empty
|
@empty
|
||||||
<div class="col-span-full">
|
<div class="col-span-full">
|
||||||
<x-filament::empty-state
|
<x-filament::empty-state icon="heroicon-o-inbox" :heading="$this->getEmptyStateHeading()" :description="$this->getEmptyStateDescription()"
|
||||||
icon="heroicon-o-inbox"
|
|
||||||
:heading="$this->getEmptyStateHeading()"
|
|
||||||
:description="$this->getEmptyStateDescription()"
|
|
||||||
icon-color="gray">
|
icon-color="gray">
|
||||||
</x-filament::empty-state>
|
</x-filament::empty-state>
|
||||||
</div>
|
</div>
|
||||||
@ -279,4 +306,5 @@ class="flex items-center gap-1 text-xs text-danger-600 dark:text-danger-400 font
|
|||||||
@endif
|
@endif
|
||||||
|
|
||||||
<x-filament-actions::modals />
|
<x-filament-actions::modals />
|
||||||
|
</x-filament::section>
|
||||||
</x-filament-panels::page>
|
</x-filament-panels::page>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user