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', }, ], ]; } }