simedkom/app/Filament/Pages/CustomVerification.php

436 lines
16 KiB
PHP

<?php
namespace App\Filament\Pages;
use App\Enums\DecisionAdmin;
use App\Enums\VerificationStatus;
use App\Filament\Resources\Manage\Journalists\Pages\ManageJournalists;
use App\Models\Company;
use App\Models\Journalist;
use App\Models\PartnerMedia;
use App\Models\VerificationRequest;
use BackedEnum;
use BezhanSalleh\FilamentShield\Traits\HasPageShield;
use Filament\Actions\Action;
use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Illuminate\Support\Collection;
use UnitEnum;
class CustomVerification extends Page implements HasActions, HasForms
{
use HasPageShield, InteractsWithActions, InteractsWithForms;
protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-check-badge';
protected static ?string $title = 'Verifikasi';
protected static ?string $navigationLabel = 'Verifikasi';
protected static string|UnitEnum|null $navigationGroup = 'Kelola';
protected static ?string $slug = 'manage/verification';
protected static ?int $navigationSort = 12;
protected string $view = 'filament.pages.verification';
public ?Company $company = null;
public ?PartnerMedia $partnerMedia = null;
public ?Journalist $journalist = null;
public ?VerificationRequest $companyVerification = null;
public ?VerificationRequest $mediaVerification = null;
public ?VerificationRequest $journalistVerification = null;
public function mount(): void
{
$this->company = auth()->user()->company;
$this->partnerMedia = auth()->user()->company?->partnerMedia;
$this->journalist = auth()->user()->company?->partnerMedia?->journalists?->first();
// Load verification requests with reviews
if ($this->company) {
$this->companyVerification = $this->company->verificationRequest()
->with(['reviews.reviewer'])
->latest()
->first();
}
if ($this->partnerMedia) {
$this->mediaVerification = $this->partnerMedia->verificationRequest()
->with(['reviews.reviewer'])
->latest()
->first();
}
if ($this->journalist) {
$this->journalistVerification = $this->journalist->verificationRequest()
->with(['reviews.reviewer'])
->latest()
->first();
}
}
/**
* Determine the current step based on status
*/
protected function resolveStep(?VerificationStatus $status, bool $hasData = false): int
{
if (! $hasData) {
return 1; // No data yet
}
return match ($status) {
VerificationStatus::PENDING,
VerificationStatus::NEED_REVISION => 2, // In review or needs revision
VerificationStatus::APPROVED,
VerificationStatus::REJECTED => 3, // Final decision
default => 1, // Draft / not submitted yet
};
}
/**
* Check if user can submit verification for entity
*/
protected function canSubmit($entity, ?VerificationRequest $verification): bool
{
if (! $entity) {
return false;
}
// No verification yet - can submit
if (! $verification) {
return true;
}
// Can resubmit only if status is NEED_REVISION
return $verification->status === VerificationStatus::NEED_REVISION;
}
/**
* Check if entity is approved
*/
protected function isApproved(?VerificationRequest $verification): bool
{
return $verification?->status === VerificationStatus::APPROVED;
}
/**
* Check if entity is rejected
*/
protected function isRejected(?VerificationRequest $verification): bool
{
return $verification?->status === VerificationStatus::REJECTED;
}
/**
* Check if entity is pending review
*/
protected function isPending(?VerificationRequest $verification): bool
{
return $verification?->status === VerificationStatus::PENDING;
}
/**
* Check if entity needs revision
*/
protected function needsRevision(?VerificationRequest $verification): bool
{
return $verification?->status === VerificationStatus::NEED_REVISION;
}
/**
* Get the latest review notes for an entity
*/
protected function getLatestReviewNotes(?VerificationRequest $verification): ?string
{
if (! $verification) {
return null;
}
$latestReview = $verification->reviews()
->whereIn('decision', [DecisionAdmin::NEED_REVISION, DecisionAdmin::REJECTED])
->latest()
->first();
return $latestReview?->note;
}
/**
* Get all reviews history for an entity
*/
protected function getReviewHistory(?VerificationRequest $verification): Collection
{
if (! $verification) {
return collect();
}
return $verification->reviews()
->with('reviewer')
->latest()
->get();
}
public function companyProgress(): array
{
$hasData = $this->company !== null;
$currentStep = $this->resolveStep($this->companyVerification?->status, $hasData);
return [
'title' => 'Perusahaan',
'description' => 'Progress verifikasi perusahaan',
'icon' => 'heroicon-o-building-office-2',
'currentStep' => $currentStep,
'entity' => $this->company,
'verification' => $this->companyVerification,
'canSubmit' => $this->canSubmit($this->company, $this->companyVerification),
'isApproved' => $this->isApproved($this->companyVerification),
'isRejected' => $this->isRejected($this->companyVerification),
'isPending' => $this->isPending($this->companyVerification),
'needsRevision' => $this->needsRevision($this->companyVerification),
'latestNotes' => $this->getLatestReviewNotes($this->companyVerification),
'reviewHistory' => $this->getReviewHistory($this->companyVerification),
'editUrl' => CustomCompany::getUrl(),
'steps' => [
[
'title' => 'Pengajuan',
'description' => $hasData ? 'Data perusahaan sudah diisi' : 'Lengkapi data perusahaan',
],
[
'title' => 'Verifikasi',
'description' => match ($this->companyVerification?->status) {
VerificationStatus::NEED_REVISION => 'Perlu perbaikan data',
VerificationStatus::PENDING => 'Sedang diverifikasi admin',
default => 'Menunggu pengajuan',
},
],
[
'title' => 'Selesai',
'description' => match ($this->companyVerification?->status) {
VerificationStatus::APPROVED => 'Perusahaan disetujui',
VerificationStatus::REJECTED => 'Perusahaan ditolak',
default => 'Menunggu keputusan',
},
],
],
];
}
public function mediaProgress(): array
{
$hasData = $this->partnerMedia !== null;
$currentStep = $this->resolveStep($this->mediaVerification?->status, $hasData);
return [
'title' => 'Media',
'description' => 'Progress verifikasi media',
'currentStep' => $currentStep,
'entity' => $this->partnerMedia,
'verification' => $this->mediaVerification,
'canSubmit' => $this->canSubmit($this->partnerMedia, $this->mediaVerification),
'isApproved' => $this->isApproved($this->mediaVerification),
'isRejected' => $this->isRejected($this->mediaVerification),
'isPending' => $this->isPending($this->mediaVerification),
'needsRevision' => $this->needsRevision($this->mediaVerification),
'latestNotes' => $this->getLatestReviewNotes($this->mediaVerification),
'reviewHistory' => $this->getReviewHistory($this->mediaVerification),
'editUrl' => CustomMedia::getUrl(),
'steps' => [
[
'title' => 'Pengajuan',
'description' => $hasData ? 'Data media sudah diisi' : 'Lengkapi data media',
],
[
'title' => 'Verifikasi',
'description' => match ($this->mediaVerification?->status) {
VerificationStatus::NEED_REVISION => 'Perlu perbaikan data',
VerificationStatus::PENDING => 'Sedang diverifikasi admin',
default => 'Menunggu pengajuan',
},
],
[
'title' => 'Selesai',
'description' => match ($this->mediaVerification?->status) {
VerificationStatus::APPROVED => 'Media disetujui',
VerificationStatus::REJECTED => 'Media ditolak',
default => 'Menunggu keputusan',
},
],
],
];
}
public function journalistProgress(): array
{
$hasData = $this->journalist !== null;
$currentStep = $this->resolveStep($this->journalistVerification?->status, $hasData);
return [
'title' => 'Jurnalis',
'description' => 'Progress verifikasi jurnalis',
'currentStep' => $currentStep,
'entity' => $this->journalist,
'verification' => $this->journalistVerification,
'canSubmit' => $this->canSubmit($this->journalist, $this->journalistVerification),
'isApproved' => $this->isApproved($this->journalistVerification),
'isRejected' => $this->isRejected($this->journalistVerification),
'isPending' => $this->isPending($this->journalistVerification),
'needsRevision' => $this->needsRevision($this->journalistVerification),
'latestNotes' => $this->getLatestReviewNotes($this->journalistVerification),
'reviewHistory' => $this->getReviewHistory($this->journalistVerification),
'editUrl' => ManageJournalists::getUrl(),
'steps' => [
[
'title' => 'Pengajuan',
'description' => $hasData ? 'Data jurnalis sudah diisi' : 'Lengkapi data jurnalis',
],
[
'title' => 'Verifikasi',
'description' => match ($this->journalistVerification?->status) {
VerificationStatus::NEED_REVISION => 'Perlu perbaikan data',
VerificationStatus::PENDING => 'Sedang diverifikasi admin',
default => 'Menunggu pengajuan',
},
],
[
'title' => 'Selesai',
'description' => match ($this->journalistVerification?->status) {
VerificationStatus::APPROVED => 'Jurnalis disetujui',
VerificationStatus::REJECTED => 'Jurnalis ditolak',
default => 'Menunggu keputusan',
},
],
],
];
}
/**
* Submit company verification action
*/
public function submitCompanyAction(): Action
{
return Action::make('submitCompany')
->label(fn () => $this->needsRevision($this->companyVerification) ? 'Kirim Ulang' : 'Ajukan Verifikasi')
->icon('heroicon-o-paper-airplane')
->color('primary')
->requiresConfirmation()
->modalHeading('Ajukan Verifikasi Perusahaan')
->modalDescription('Apakah Anda yakin ingin mengajukan data perusahaan untuk diverifikasi? Pastikan semua data sudah benar.')
->modalSubmitActionLabel('Ya, Ajukan')
->visible(fn () => $this->canSubmit($this->company, $this->companyVerification))
->action(function () {
$this->submitVerification('company', $this->company, $this->companyVerification);
});
}
/**
* Submit media verification action
*/
public function submitMediaAction(): Action
{
return Action::make('submitMedia')
->label(fn () => $this->needsRevision($this->mediaVerification) ? 'Kirim Ulang' : 'Ajukan Verifikasi')
->icon('heroicon-o-paper-airplane')
->color('primary')
->requiresConfirmation()
->modalHeading('Ajukan Verifikasi Media')
->modalDescription('Apakah Anda yakin ingin mengajukan data media untuk diverifikasi? Pastikan semua data sudah benar.')
->modalSubmitActionLabel('Ya, Ajukan')
->visible(fn () => $this->canSubmit($this->partnerMedia, $this->mediaVerification))
->action(function () {
$this->submitVerification('media', $this->partnerMedia, $this->mediaVerification);
});
}
/**
* Submit journalist verification action
*/
public function submitJournalistAction(): Action
{
return Action::make('submitJournalist')
->label(fn () => $this->needsRevision($this->journalistVerification) ? 'Kirim Ulang' : 'Ajukan Verifikasi')
->icon('heroicon-o-paper-airplane')
->color('primary')
->requiresConfirmation()
->modalHeading('Ajukan Verifikasi Jurnalis')
->modalDescription('Apakah Anda yakin ingin mengajukan data jurnalis untuk diverifikasi? Pastikan semua data sudah benar.')
->modalSubmitActionLabel('Ya, Ajukan')
->visible(fn () => $this->canSubmit($this->journalist, $this->journalistVerification))
->action(function () {
$this->submitVerification('journalist', $this->journalist, $this->journalistVerification);
});
}
/**
* Handle verification submission
*/
protected function submitVerification(string $type, $entity, ?VerificationRequest $existingRequest): void
{
if (! $entity) {
Notification::make()
->title('Error')
->body('Data tidak ditemukan. Silakan lengkapi data terlebih dahulu.')
->danger()
->send();
return;
}
if ($existingRequest && $existingRequest->status === VerificationStatus::NEED_REVISION) {
// Resubmit - update existing request
$existingRequest->update([
'status' => VerificationStatus::PENDING,
]);
$verification = $existingRequest;
} else {
// New submission
$verification = VerificationRequest::create([
'verifiable_type' => get_class($entity),
'verifiable_id' => $entity->id,
'submitted_by' => auth()->id(),
'status' => VerificationStatus::PENDING,
]);
}
// Update the local property
match ($type) {
'company' => $this->companyVerification = $verification->fresh(['reviews.reviewer']),
'media' => $this->mediaVerification = $verification->fresh(['reviews.reviewer']),
'journalist' => $this->journalistVerification = $verification->fresh(['reviews.reviewer']),
};
$entityName = match ($type) {
'company' => 'Perusahaan',
'media' => 'Media',
'journalist' => 'Jurnalis',
};
Notification::make()
->title('Berhasil!')
->body("Data {$entityName} berhasil diajukan untuk diverifikasi.")
->success()
->send();
}
public function getViewData(): array
{
return [
'companyProgress' => $this->companyProgress(),
'mediaProgress' => $this->mediaProgress(),
'journalistProgress' => $this->journalistProgress(),
];
}
}