434 lines
16 KiB
PHP
434 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 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(),
|
|
];
|
|
}
|
|
}
|