refactor: replace Verification page with a new Index page and associated services for improved structure, maintainability, and functionality in the verification process

This commit is contained in:
Yoga Pangestu 2026-04-08 14:11:31 +07:00
parent 20dcd0e981
commit d220f941c1
6 changed files with 600 additions and 432 deletions

View File

@ -1,432 +0,0 @@
<?php
namespace App\Filament\Pages;
use App\Enums\VerificationStatus;
use App\Filament\Pages\Company as PagesCompany;
use App\Filament\Resources\Manage\Journalists\Pages\ManageJournalists;
use App\Filament\Resources\Manage\Partners\PartnerResource;
use App\Filament\Support\CheerfulNotification;
use App\Models\Company;
use App\Models\User;
use App\Models\VerificationRequest;
use App\Notifications\BroadcastNotification;
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\Pages\Page;
use Filament\Support\Icons\Heroicon;
use Illuminate\Support\Collection;
use UnitEnum;
class Verification extends Page implements HasActions, HasForms
{
use HasPageShield, InteractsWithActions, InteractsWithForms;
public ?Company $company = null;
protected static string|UnitEnum|null $navigationGroup = 'Kelola';
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedCheckBadge;
protected static ?string $navigationLabel = 'Verifikasi';
protected static ?int $navigationSort = 5;
protected static ?string $slug = 'manage/verification';
protected static ?string $title = 'Verifikasi';
public ?VerificationRequest $verificationRequest = null;
protected string $view = 'filament.pages.verification';
public function mount(): void
{
$user = auth()->user();
$this->company = $user->company;
// Load unified verification request
if ($this->company) {
$this->verificationRequest = $this->company->verificationRequest()
->with(['reviews.reviewer'])
->latest()
->first();
}
}
/**
* Get unified verification progress
*/
public function getVerificationProgress(): array
{
$isComplete = $this->isDataComplete();
$missingData = $this->getMissingData();
$status = $this->verificationRequest?->status;
$progress = [
'currentStep' => $this->resolveStep(),
'isDataComplete' => $isComplete,
'missingData' => $missingData,
'canSubmit' => $this->canSubmit(),
'verification' => $this->verificationRequest,
'status' => [
'label' => $status?->getLabel() ?? 'Belum Mengajukan',
'color' => $status?->getColor() ?? 'gray',
],
'isApproved' => $status === VerificationStatus::APPROVED,
'isRejected' => $status === VerificationStatus::REJECTED,
'isPending' => $status === VerificationStatus::PENDING,
'needsRevision' => $status === VerificationStatus::NEED_REVISION,
'latestNotes' => $this->getLatestReviewNotes(),
'reviewHistory' => $this->getReviewHistory(),
'company' => $this->company,
'partnerMedia' => $this->company?->partnerMedia,
'journalists' => $this->company?->partnerMedia?->journalists ?? collect(),
'steps' => $this->getSteps($isComplete),
];
// Add additional data for view
$progress['missingDataButtons'] = $this->getMissingDataButtons();
$progress['alert'] = $this->getAlertData();
$progress['lastSubmittedAt'] = $this->verificationRequest?->updated_at?->translatedFormat('l, d M Y H:i');
return $progress;
}
/**
* Submit unified verification action
*/
public function submitVerificationAction(): Action
{
$progress = $this->getVerificationProgress();
return Action::make('submitVerification')
->label(fn (): string => $this->verificationRequest && $this->verificationRequest->status === VerificationStatus::NEED_REVISION
? 'Kirim Ulang'
: 'Ajukan Verifikasi')
->icon('heroicon-o-paper-airplane')
->color('primary')
->requiresConfirmation()
->modalHeading(fn () => CheerfulNotification::getByKey('verification.submit.title'))
->modalDescription(function () use ($progress): string {
if (! $progress['isDataComplete']) {
return CheerfulNotification::getByKey('verification.submit.description.incomplete', ['missing' => implode(', ', $progress['missingData'])]);
}
if ($this->verificationRequest && $this->verificationRequest->status === VerificationStatus::NEED_REVISION) {
return CheerfulNotification::getByKey('verification.submit.description.revision');
}
return CheerfulNotification::getByKey('verification.submit.description.default');
})
->modalSubmitActionLabel('Ya, Ajukan')
->visible(fn (): bool => $progress['canSubmit'])
->disabled(fn (): bool => ! $progress['isDataComplete'])
->action(function () use ($progress): void {
if (! $progress['isDataComplete']) {
CheerfulNotification::danger(
CheerfulNotification::getByKey('verification.incomplete.title'),
CheerfulNotification::getByKey('verification.incomplete.body', ['missing' => implode(', ', $progress['missingData'])])
)->send();
return;
}
$isRevision = $this->verificationRequest && $this->verificationRequest->status === VerificationStatus::NEED_REVISION;
$this->verificationRequest = $this->submitVerification();
CheerfulNotification::success(
CheerfulNotification::getByKey('verification.success.title'),
CheerfulNotification::getByKey('verification.success.body')
)->send();
User::superAdmin()
->get()
->each(function ($admin) use ($isRevision): void {
$user = auth()->user();
$admin->notify(new BroadcastNotification([
'title' => $isRevision
? CheerfulNotification::getByKey('verification.admin_notify.title.revision')
: CheerfulNotification::getByKey('verification.admin_notify.title.new'),
'body' => $isRevision
? CheerfulNotification::getByKey('verification.admin_notify.body.revision', ['name' => $user->name, 'company' => $user->company->name])
: CheerfulNotification::getByKey('verification.admin_notify.body.new', ['name' => $user->name, 'company' => $user->company->name]),
'action' => [
Action::make('view')
->label('Lihat')
->url(PartnerResource::getUrl('view', ['record' => $user])),
],
]));
});
});
}
/**
* Check if all required data is complete for verification
*/
protected function isDataComplete(): bool
{
return $this->company !== null
&& $this->company->partnerMedia !== null
&& $this->company->partnerMedia?->journalists !== null
&& $this->company->partnerMedia->journalists->count() > 0;
}
/**
* Get missing data items for verification
*/
protected function getMissingData(): array
{
$missing = [];
if (! $this->company) {
$missing[] = 'Data Perusahaan';
}
if ($this->company && ! $this->company->partnerMedia) {
$missing[] = 'Data Media';
}
if ($this->company && $this->company->partnerMedia && ($this->company->partnerMedia?->journalists === null || $this->company->partnerMedia?->journalists?->count() === 0)) {
$missing[] = 'Data Jurnalis (minimal 1)';
}
return $missing;
}
/**
* Check if user can submit verification
*/
protected function canSubmit(): bool
{
if (! $this->isDataComplete()) {
return false;
}
// No verification yet - can submit
if (! $this->verificationRequest) {
return true;
}
// Can resubmit only if status is NEED_REVISION
return $this->verificationRequest->status === VerificationStatus::NEED_REVISION;
}
/**
* Determine the current step based on status
*/
protected function resolveStep(): int
{
if (! $this->isDataComplete()) {
return 1; // Data belum lengkap
}
if (! $this->verificationRequest) {
return 1; // Belum submit
}
return match ($this->verificationRequest->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
};
}
/**
* Get the latest review notes
*/
protected function getLatestReviewNotes(): ?string
{
if (! $this->verificationRequest) {
return null;
}
$latestReview = $this->verificationRequest->reviews()
->where(fn ($q) => $q->needRevision()->orWhere(fn ($q) => $q->rejected()))
->latest()
->first();
return $latestReview?->note;
}
/**
* Get all reviews history
*/
protected function getReviewHistory(): Collection
{
if (! $this->verificationRequest) {
return collect();
}
return $this->verificationRequest->reviews()
->with('reviewer')
->latest()
->get();
}
/**
* Submit unified verification
*/
protected function submitVerification(): VerificationRequest
{
if ($this->verificationRequest && $this->verificationRequest->status === VerificationStatus::NEED_REVISION) {
// Resubmit - update existing request
$this->verificationRequest->update([
'status' => VerificationStatus::PENDING,
]);
return $this->verificationRequest->fresh(['reviews.reviewer']);
}
// New submission
return VerificationRequest::create([
'company_id' => $this->company->id,
'submitted_by' => auth()->id(),
'status' => VerificationStatus::PENDING,
])->load(['reviews.reviewer']);
}
/**
* Get alert data for verification status
*/
protected function getAlertData(): ?array
{
if (! $this->verificationRequest) {
return null;
}
$status = $this->verificationRequest->status;
$latestNotes = $this->getLatestReviewNotes();
if ($status === VerificationStatus::NEED_REVISION && $latestNotes) {
return [
'type' => 'revision',
'icon' => 'exclamation-triangle',
'title' => 'Catatan Revisi dari Admin',
'message' => $latestNotes,
'color' => 'warning',
];
}
if ($status === VerificationStatus::REJECTED && $latestNotes) {
return [
'type' => 'rejected',
'icon' => 'x-circle',
'title' => 'Pengajuan Ditolak',
'message' => $latestNotes,
'color' => 'danger',
];
}
if ($status === VerificationStatus::APPROVED) {
return [
'type' => 'approved',
'icon' => 'check-circle',
'title' => 'Verifikasi Diterima',
'message' => CheerfulNotification::getByKey('verification.alert.approved.body'),
'color' => 'success',
];
}
if ($status === VerificationStatus::PENDING) {
return [
'type' => 'pending',
'icon' => 'clock',
'title' => CheerfulNotification::getByKey('verification.alert.pending.title'),
'message' => CheerfulNotification::getByKey('verification.alert.pending.body'),
'color' => 'info',
'animate' => true,
];
}
return null;
}
/**
* Get missing data buttons configuration
*/
protected function getMissingDataButtons(): array
{
$buttons = [];
if (! $this->company) {
$buttons[] = [
'label' => 'Lengkapi Data Perusahaan',
'url' => PagesCompany::getUrl(),
'icon' => 'building-office-2',
'color' => 'warning',
];
}
if ($this->company && ! $this->company->partnerMedia) {
$buttons[] = [
'label' => 'Lengkapi Data Media',
'url' => Media::getUrl(),
'icon' => 'newspaper',
'color' => 'warning',
];
}
if ($this->company && $this->company->partnerMedia && ($this->company->partnerMedia->journalists === null || $this->company->partnerMedia->journalists->count() === 0)) {
$buttons[] = [
'label' => 'Lengkapi Data Jurnalis',
'url' => ManageJournalists::getUrl(),
'icon' => 'user-circle',
'color' => 'warning',
];
}
return $buttons;
}
/**
* Get steps array for stepper
*/
protected function getSteps(bool $isComplete): array
{
$status = $this->verificationRequest?->status;
return [
[
'title' => 'Pengajuan',
'description' => $isComplete
? 'Data sudah lengkap, silakan ajukan verifikasi'
: 'Silakan lengkapi data',
],
[
'title' => 'Verifikasi',
'description' => match ($status) {
VerificationStatus::NEED_REVISION => 'Perlu perbaikan data',
VerificationStatus::PENDING => 'Sedang diverifikasi admin',
default => 'Menunggu pengajuan',
},
],
[
'title' => 'Selesai',
'description' => match ($status) {
VerificationStatus::APPROVED => 'Verifikasi disetujui',
VerificationStatus::REJECTED => 'Verifikasi ditolak',
default => 'Menunggu keputusan',
},
],
];
}
public function getViewData(): array
{
return [
'verificationProgress' => $this->getVerificationProgress(),
];
}
}

View File

@ -0,0 +1,61 @@
<?php
namespace App\Filament\Pages\Verification\Actions;
use App\Enums\VerificationStatus;
use App\Filament\Support\CheerfulNotification;
use Filament\Actions\Action;
class SubmitVerificationAction extends Action
{
public static function getDefaultName(): ?string
{
return 'submitVerification';
}
protected function setUp(): void
{
parent::setUp();
$this->label(function (): string {
$progress = $this->getLivewire()->getVerificationProgress();
$verification = $progress['verification'];
return $verification && $verification->status === VerificationStatus::NEED_REVISION
? 'Kirim Ulang'
: 'Ajukan Verifikasi';
})
->icon('heroicon-o-paper-airplane')
->color('primary')
->requiresConfirmation()
->modalHeading(fn () => CheerfulNotification::getByKey('verification.submit.title'))
->modalDescription(function (): string {
$progress = $this->getLivewire()->getVerificationProgress();
if (! $progress['isDataComplete']) {
return CheerfulNotification::getByKey(
'verification.submit.description.incomplete',
['missing' => implode(', ', $progress['missingData'])]
);
}
$verification = $progress['verification'];
if ($verification && $verification->status === VerificationStatus::NEED_REVISION) {
return CheerfulNotification::getByKey('verification.submit.description.revision');
}
return CheerfulNotification::getByKey('verification.submit.description.default');
})
->modalSubmitActionLabel('Ya, Ajukan')
->visible(function (): bool {
return $this->getLivewire()->getVerificationProgress()['canSubmit'];
})
->disabled(function (): bool {
return ! $this->getLivewire()->getVerificationProgress()['isDataComplete'];
})
->action(function (array $data = []): void {
$this->getLivewire()->handleVerificationSubmit($data);
});
}
}

View File

@ -0,0 +1,216 @@
<?php
namespace App\Filament\Pages\Verification;
use App\Enums\VerificationStatus;
use App\Filament\Pages\Verification\Actions\SubmitVerificationAction;
use App\Filament\Pages\Verification\Services\VerificationAdminNotifier;
use App\Filament\Pages\Verification\Services\VerificationProgressService;
use App\Filament\Pages\Verification\Services\VerificationSubmissionService;
use App\Filament\Support\CheerfulNotification;
use App\Models\Company;
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\Pages\Page;
use Filament\Support\Icons\Heroicon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use UnitEnum;
class Index extends Page implements HasActions, HasForms
{
use HasPageShield, InteractsWithActions, InteractsWithForms;
public ?Company $company = null;
protected static string|UnitEnum|null $navigationGroup = 'Kelola';
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedCheckBadge;
protected static ?string $navigationLabel = 'Verifikasi';
protected static ?int $navigationSort = 5;
protected static ?string $slug = 'manage/verification';
protected static ?string $title = 'Verifikasi';
public ?VerificationRequest $verificationRequest = null;
protected string $view = 'filament.pages.verification';
public static function canAccess(): bool
{
return auth()->user()->can('View:Verification');
}
public function mount(): void
{
$user = Auth::user();
$this->company = $user->company;
// Load unified verification request
if ($this->company) {
$this->verificationRequest = $this->company->verificationRequest()
->with(['reviews.reviewer'])
->latest()
->first();
}
}
/**
* Get unified verification progress
*/
public function getVerificationProgress(): array
{
return app(VerificationProgressService::class)->getProgress(
$this->company,
$this->verificationRequest,
);
}
/**
* Submit unified verification action
*/
public function submitVerificationAction(): Action
{
return SubmitVerificationAction::make();
}
public function handleVerificationSubmit(array $data = []): void
{
$user = Auth::user();
$progress = app(VerificationProgressService::class)->getProgress(
$this->company,
$this->verificationRequest,
);
if (! $progress['isDataComplete']) {
CheerfulNotification::danger(
CheerfulNotification::getByKey('verification.incomplete.title'),
CheerfulNotification::getByKey(
'verification.incomplete.body',
['missing' => implode(', ', $progress['missingData'])]
)
)->send();
return;
}
$isRevision = $this->verificationRequest && $this->verificationRequest->status === VerificationStatus::NEED_REVISION;
$this->verificationRequest = app(VerificationSubmissionService::class)->submit(
$this->company,
$this->verificationRequest,
$user,
);
CheerfulNotification::success(
CheerfulNotification::getByKey('verification.success.title'),
CheerfulNotification::getByKey('verification.success.body')
)->send();
app(VerificationAdminNotifier::class)->notifySuperAdmins($user, $isRevision);
}
/**
* Check if all required data is complete for verification
*/
protected function isDataComplete(): bool
{
return app(VerificationProgressService::class)->isDataComplete($this->company);
}
/**
* Get missing data items for verification
*/
protected function getMissingData(): array
{
return app(VerificationProgressService::class)->getMissingData($this->company);
}
/**
* Check if user can submit verification
*/
protected function canSubmit(): bool
{
return app(VerificationProgressService::class)->canSubmit($this->company, $this->verificationRequest);
}
/**
* Determine the current step based on status
*/
protected function resolveStep(): int
{
return app(VerificationProgressService::class)->resolveStep($this->company, $this->verificationRequest);
}
/**
* Get the latest review notes
*/
protected function getLatestReviewNotes(): ?string
{
return app(VerificationProgressService::class)->getLatestReviewNotes($this->verificationRequest);
}
/**
* Get all reviews history
*/
protected function getReviewHistory(): Collection
{
return app(VerificationProgressService::class)->getReviewHistory($this->verificationRequest);
}
/**
* Submit unified verification
*/
protected function submitVerification(): VerificationRequest
{
return app(VerificationSubmissionService::class)->submit(
$this->company,
$this->verificationRequest,
Auth::user(),
);
}
/**
* Get alert data for verification status
*/
protected function getAlertData(): ?array
{
return app(VerificationProgressService::class)->getAlertData($this->verificationRequest);
}
/**
* Get missing data buttons configuration
*/
protected function getMissingDataButtons(): array
{
return app(VerificationProgressService::class)->getMissingDataButtons($this->company);
}
/**
* Get steps array for stepper
*/
protected function getSteps(bool $isComplete): array
{
return app(VerificationProgressService::class)->getSteps(
$this->company,
$this->verificationRequest,
$isComplete
);
}
public function getViewData(): array
{
return [
'verificationProgress' => $this->getVerificationProgress(),
];
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace App\Filament\Pages\Verification\Services;
use App\Filament\Resources\Manage\Partners\PartnerResource;
use App\Filament\Support\CheerfulNotification;
use App\Models\User;
use App\Notifications\BroadcastNotification;
use Filament\Actions\Action;
class VerificationAdminNotifier
{
public function notifySuperAdmins(User $actor, bool $isRevision): void
{
$companyName = $actor->company?->name;
User::superAdmin()->get()->each(function (User $admin) use ($actor, $companyName, $isRevision): void {
$admin->notify(new BroadcastNotification([
'title' => $isRevision
? CheerfulNotification::getByKey('verification.admin_notify.title.revision')
: CheerfulNotification::getByKey('verification.admin_notify.title.new'),
'body' => $isRevision
? CheerfulNotification::getByKey('verification.admin_notify.body.revision', ['name' => $actor->name, 'company' => $companyName])
: CheerfulNotification::getByKey('verification.admin_notify.body.new', ['name' => $actor->name, 'company' => $companyName]),
'action' => [
Action::make('view')
->label('Lihat')
->url(PartnerResource::getUrl('view', ['record' => $actor])),
],
]));
});
}
}

View File

@ -0,0 +1,260 @@
<?php
namespace App\Filament\Pages\Verification\Services;
use App\Enums\VerificationStatus;
use App\Filament\Pages\Company\Index as CompanyPage;
use App\Filament\Pages\Media\Index as MediaPage;
use App\Filament\Resources\Manage\Journalists\Pages\ManageJournalists;
use App\Filament\Support\CheerfulNotification;
use App\Models\Company;
use App\Models\VerificationRequest;
use Illuminate\Support\Collection as SupportCollection;
class VerificationProgressService
{
public function getProgress(?Company $company, ?VerificationRequest $verificationRequest): array
{
$isComplete = $this->isDataComplete($company);
$missingData = $this->getMissingData($company);
$status = $verificationRequest?->status;
$progress = [
'currentStep' => $this->resolveStep($company, $verificationRequest),
'isDataComplete' => $isComplete,
'missingData' => $missingData,
'canSubmit' => $this->canSubmit($company, $verificationRequest),
'verification' => $verificationRequest,
'status' => [
'label' => $status?->getLabel() ?? 'Belum Mengajukan',
'color' => $status?->getColor() ?? 'gray',
],
'isApproved' => $status === VerificationStatus::APPROVED,
'isRejected' => $status === VerificationStatus::REJECTED,
'isPending' => $status === VerificationStatus::PENDING,
'needsRevision' => $status === VerificationStatus::NEED_REVISION,
'latestNotes' => $this->getLatestReviewNotes($verificationRequest),
'reviewHistory' => $this->getReviewHistory($verificationRequest),
'company' => $company,
'partnerMedia' => $company?->partnerMedia,
'journalists' => $company?->partnerMedia?->journalists ?? collect(),
'steps' => $this->getSteps($company, $verificationRequest, $isComplete),
];
$progress['missingDataButtons'] = $this->getMissingDataButtons($company);
$progress['alert'] = $this->getAlertData($verificationRequest);
$progress['lastSubmittedAt'] = $verificationRequest?->updated_at?->translatedFormat('l, d M Y H:i');
return $progress;
}
public function isDataComplete(?Company $company): bool
{
return $company !== null
&& $company->partnerMedia !== null
&& $company->partnerMedia?->journalists !== null
&& $company->partnerMedia->journalists->count() > 0;
}
public function getMissingData(?Company $company): array
{
$missing = [];
if (! $company) {
$missing[] = 'Data Perusahaan';
return $missing;
}
if (! $company->partnerMedia) {
$missing[] = 'Data Media';
}
if ($company->partnerMedia && ($company->partnerMedia?->journalists === null || $company->partnerMedia?->journalists?->count() === 0)) {
$missing[] = 'Data Jurnalis (minimal 1)';
}
return $missing;
}
public function canSubmit(?Company $company, ?VerificationRequest $verificationRequest): bool
{
if (! $this->isDataComplete($company)) {
return false;
}
// No verification yet - can submit
if (! $verificationRequest) {
return true;
}
// Can resubmit only if status is NEED_REVISION
return $verificationRequest->status === VerificationStatus::NEED_REVISION;
}
public function resolveStep(?Company $company, ?VerificationRequest $verificationRequest): int
{
if (! $this->isDataComplete($company)) {
return 1; // Data belum lengkap
}
if (! $verificationRequest) {
return 1; // Belum submit
}
return match ($verificationRequest->status) {
VerificationStatus::PENDING,
VerificationStatus::NEED_REVISION => 2, // In review or needs revision
VerificationStatus::APPROVED,
VerificationStatus::REJECTED => 3, // Final decision
default => 1,
};
}
public function getLatestReviewNotes(?VerificationRequest $verificationRequest): ?string
{
if (! $verificationRequest) {
return null;
}
$latestReview = $verificationRequest->reviews()
->where(fn ($q) => $q->needRevision()->orWhere(fn ($q) => $q->rejected()))
->latest()
->first();
return $latestReview?->note;
}
public function getReviewHistory(?VerificationRequest $verificationRequest): SupportCollection
{
if (! $verificationRequest) {
return collect();
}
return $verificationRequest->reviews()
->with('reviewer')
->latest()
->get();
}
public function getAlertData(?VerificationRequest $verificationRequest): ?array
{
if (! $verificationRequest) {
return null;
}
$status = $verificationRequest->status;
$latestNotes = $this->getLatestReviewNotes($verificationRequest);
if ($status === VerificationStatus::NEED_REVISION && $latestNotes) {
return [
'type' => 'revision',
'icon' => 'exclamation-triangle',
'title' => 'Catatan Revisi dari Admin',
'message' => $latestNotes,
'color' => 'warning',
];
}
if ($status === VerificationStatus::REJECTED && $latestNotes) {
return [
'type' => 'rejected',
'icon' => 'x-circle',
'title' => 'Pengajuan Ditolak',
'message' => $latestNotes,
'color' => 'danger',
];
}
if ($status === VerificationStatus::APPROVED) {
return [
'type' => 'approved',
'icon' => 'check-circle',
'title' => 'Verifikasi Diterima',
'message' => CheerfulNotification::getByKey('verification.alert.approved.body'),
'color' => 'success',
];
}
if ($status === VerificationStatus::PENDING) {
return [
'type' => 'pending',
'icon' => 'clock',
'title' => CheerfulNotification::getByKey('verification.alert.pending.title'),
'message' => CheerfulNotification::getByKey('verification.alert.pending.body'),
'color' => 'info',
'animate' => true,
];
}
return null;
}
public function getMissingDataButtons(?Company $company): array
{
$buttons = [];
if (! $company) {
$buttons[] = [
'label' => 'Lengkapi Data Perusahaan',
'url' => CompanyPage::getUrl(),
'icon' => 'building-office-2',
'color' => 'warning',
];
return $buttons;
}
if (! $company->partnerMedia) {
$buttons[] = [
'label' => 'Lengkapi Data Media',
'url' => MediaPage::getUrl(),
'icon' => 'newspaper',
'color' => 'warning',
];
}
if ($company->partnerMedia && ($company->partnerMedia->journalists === null || $company->partnerMedia->journalists->count() === 0)) {
$buttons[] = [
'label' => 'Lengkapi Data Jurnalis',
'url' => ManageJournalists::getUrl(),
'icon' => 'user-circle',
'color' => 'warning',
];
}
return $buttons;
}
public function getSteps(?Company $company, ?VerificationRequest $verificationRequest, bool $isComplete): array
{
$status = $verificationRequest?->status;
return [
[
'title' => 'Pengajuan',
'description' => $isComplete
? 'Data sudah lengkap, silakan ajukan verifikasi'
: 'Silakan lengkapi data',
],
[
'title' => 'Verifikasi',
'description' => match ($status) {
VerificationStatus::NEED_REVISION => 'Perlu perbaikan data',
VerificationStatus::PENDING => 'Sedang diverifikasi admin',
default => 'Menunggu pengajuan',
},
],
[
'title' => 'Selesai',
'description' => match ($status) {
VerificationStatus::APPROVED => 'Verifikasi disetujui',
VerificationStatus::REJECTED => 'Verifikasi ditolak',
default => 'Menunggu keputusan',
},
],
];
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Filament\Pages\Verification\Services;
use App\Enums\VerificationStatus;
use App\Models\Company;
use App\Models\User;
use App\Models\VerificationRequest;
class VerificationSubmissionService
{
public function submit(Company $company, ?VerificationRequest $verificationRequest, User $actor): VerificationRequest
{
if ($verificationRequest && $verificationRequest->status === VerificationStatus::NEED_REVISION) {
// Resubmit - update existing request
$verificationRequest->update([
'status' => VerificationStatus::PENDING,
]);
return $verificationRequest->fresh(['reviews.reviewer']);
}
// New submission
return VerificationRequest::create([
'company_id' => $company->id,
'submitted_by' => $actor->id,
'status' => VerificationStatus::PENDING,
])->load(['reviews.reviewer']);
}
}