436 lines
16 KiB
PHP
436 lines
16 KiB
PHP
<?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';
|
|
|
|
public function getTitle(): string
|
|
{
|
|
return CheerfulNotification::getMessage('Verifikasi 🛡️✨', 'Pengajuan 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::getMessage('Ajukan Verifikasi Sekarang? 🚀✨', 'Ajukan Verifikasi'))
|
|
->modalDescription(function () use ($progress): string {
|
|
if (! $progress['isDataComplete']) {
|
|
return CheerfulNotification::getMessage('Aduh, data belum lengkap nih! 😅 Silakan lengkapi dulu bagian: '.implode(', ', $progress['missingData']).' ya!', 'Data belum lengkap. Silakan lengkapi bagian: '.implode(', ', $progress['missingData']).'.');
|
|
}
|
|
|
|
if ($this->verificationRequest && $this->verificationRequest->status === VerificationStatus::NEED_REVISION) {
|
|
return CheerfulNotification::getMessage('Ayo kirim ulang perbaikannya! Pastikan semuanya sudah sesuai catatan admin biar langsung gaspol! 💪✨', 'Silakan kirimkan kembali perbaikan data Anda sesuai dengan catatan Admin.');
|
|
}
|
|
|
|
return CheerfulNotification::getMessage('Apakah Anda yakin ingin mengajukan verifikasi? Pastikan semua data sudah benar and lengkap ya! Pasti bisa! 😊👍', 'Apakah Anda yakin ingin mengajukan verifikasi? Pastikan seluruh data yang diinput telah sesuai.');
|
|
})
|
|
->modalSubmitActionLabel('Ya, Ajukan')
|
|
->visible(fn (): bool => $progress['canSubmit'])
|
|
->disabled(fn (): bool => ! $progress['isDataComplete'])
|
|
->action(function () use ($progress): void {
|
|
if (! $progress['isDataComplete']) {
|
|
CheerfulNotification::danger(
|
|
CheerfulNotification::getMessage('Data Belum Lengkap! 😅', 'Data Tidak Lengkap'),
|
|
CheerfulNotification::getMessage('Silakan lengkapi data terlebih dahulu sebelum mengajukan verifikasi ya: '.implode(', ', $progress['missingData']), 'Silakan lengkapi seluruh data wajib sebelum mengajukan verifikasi: '.implode(', ', $progress['missingData']))
|
|
)->send();
|
|
|
|
return;
|
|
}
|
|
|
|
$isRevision = $this->verificationRequest && $this->verificationRequest->status === VerificationStatus::NEED_REVISION;
|
|
|
|
$this->verificationRequest = $this->submitVerification();
|
|
|
|
CheerfulNotification::success(
|
|
CheerfulNotification::getMessage('Berhasil Diajukan! 🚀', 'Berhasil Diajukan'),
|
|
CheerfulNotification::getMessage('Yeay! Pengajuan verifikasi Anda sudah terkirim ke Admin. Mohon ditunggu ya, semoga hasilnya memuaskan! ✨', 'Pengajuan verifikasi Anda telah berhasil dikirimkan ke pihak Admin untuk diproses.')
|
|
)->send();
|
|
|
|
User::superAdmin()
|
|
->get()
|
|
->each(function ($admin) use ($isRevision): void {
|
|
$user = auth()->user();
|
|
|
|
$admin->notify(new BroadcastNotification([
|
|
'title' => $isRevision
|
|
? CheerfulNotification::getMessage('Pembaruan Data Verifikasi ✨', 'Pembaruan Data Verifikasi')
|
|
: CheerfulNotification::getMessage('Ada Pengajuan Verifikasi Baru! 🚀', 'Pengajuan Verifikasi Baru'),
|
|
'body' => $isRevision
|
|
? CheerfulNotification::getMessage("Cihuy! {$user->name} baru saja memperbarui data verifikasi untuk perusahaan {$user->company->name}. Yuk, cek perubahannya!", "Pengguna {$user->name} telah memperbarui data verifikasi untuk perusahaan {$user->company->name}.")
|
|
: CheerfulNotification::getMessage("Halo Admin! {$user->name} baru saja mengajukan verifikasi data untuk perusahaan {$user->company->name}. Segera diproses ya! 😊", "Pengguna {$user->name} telah mengajukan verifikasi data untuk perusahaan {$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' => 'Verifikasi Anda telah diterima dan disetujui oleh admin. Sekarang Anda sudah resmi terverifikasi dan bekerja sama dengan kami!',
|
|
'color' => 'success',
|
|
];
|
|
}
|
|
|
|
if ($status === VerificationStatus::PENDING) {
|
|
return [
|
|
'type' => 'pending',
|
|
'icon' => 'clock',
|
|
'title' => 'Menunggu Verifikasi',
|
|
'message' => 'Data Anda sedang dalam proses verifikasi oleh admin. Mohon tunggu.',
|
|
'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(),
|
|
];
|
|
}
|
|
}
|