partnerMedia !== null && $company->partnerMedia?->journalists !== null && $company->partnerMedia->journalists->count() > 0; } /** * Get missing data items for verification */ public function getMissingData(?Company $company): array { $missing = []; if (! $company) { $missing[] = 'Data Perusahaan'; } if ($company && ! $company->partnerMedia) { $missing[] = 'Data Media'; } if ($company && $company->partnerMedia && ($company->partnerMedia?->journalists === null || $company->partnerMedia?->journalists?->count() === 0)) { $missing[] = 'Data Jurnalis (minimal 1)'; } return $missing; } /** * Check if user can submit verification */ 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; } /** * Determine the current step based on status */ 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, // Draft / not submitted yet }; } /** * Get the latest review notes */ 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; } /** * Get all reviews history */ public function getReviewHistory(?VerificationRequest $verificationRequest): Collection { if (! $verificationRequest) { return collect(); } return $verificationRequest->reviews() ->with('reviewer') ->latest() ->get(); } /** * Get unified verification progress data */ public function getVerificationProgress(?Company $company, ?VerificationRequest $verificationRequest): array { $currentStep = $this->resolveStep($company, $verificationRequest); $isComplete = $this->isDataComplete($company); $missingData = $this->getMissingData($company); $status = $verificationRequest?->status; return [ 'currentStep' => $currentStep, '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($verificationRequest, $isComplete, $missingData), ]; } /** * Get steps array for stepper */ protected function getSteps(?VerificationRequest $verificationRequest, bool $isComplete, array $missingData): 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', }, ], ]; } /** * Submit unified verification */ public function submitVerification(Company $company, ?VerificationRequest $existingRequest): VerificationRequest { if ($existingRequest && $existingRequest->status === VerificationStatus::NEED_REVISION) { // Resubmit - update existing request $existingRequest->update([ 'status' => VerificationStatus::PENDING, ]); return $existingRequest->fresh(['reviews.reviewer']); } // New submission return VerificationRequest::create([ 'company_id' => $company->id, 'submitted_by' => auth()->id(), 'status' => VerificationStatus::PENDING, ])->load(['reviews.reviewer']); } /** * Process review decision - unified for Company, Media, and Journalists */ public function processReview(VerificationRequest $verificationRequest, DecisionAdmin $decision, ?string $note): void { $verificationRequest->load(['company.partnerMedia.journalists']); DB::beginTransaction(); try { // Create review record VerificationReview::create([ 'verification_request_id' => $verificationRequest->id, 'reviewer_id' => auth()->id(), 'decision' => $decision, 'note' => $note, ]); // Update verification request status $newStatus = match ($decision) { DecisionAdmin::APPROVED => VerificationStatus::APPROVED, DecisionAdmin::NEED_REVISION => VerificationStatus::NEED_REVISION, DecisionAdmin::REJECTED => VerificationStatus::REJECTED, }; $verificationRequest->update([ 'status' => $newStatus, ]); // Update Company status $company = $verificationRequest->company; if ($company) { $company->update(['status' => $newStatus]); // Update Media status $media = $company->partnerMedia; if ($media) { $media->update(['status' => $newStatus]); // Update all Journalists status $media->journalists()->update(['status' => $newStatus]); } } DB::commit(); } catch (\Exception $e) { DB::rollBack(); throw $e; } } /** * Get company name from verification request */ public function getCompanyName(VerificationRequest $request): string { return $request->company?->name ?? 'Data tidak ditemukan'; } /** * Get verification summary data for admin */ public function getVerificationSummary(VerificationRequest $request): array { $company = $request->company; $media = $company?->partnerMedia; $journalists = $media?->journalists ?? collect(); return [ 'company' => [ 'name' => $company?->name ?? 'Belum diisi', 'email' => $company?->email ?? '-', 'exists' => $company !== null, ], 'media' => [ 'name' => $media?->name ?? 'Belum diisi', 'type' => $media?->type?->getLabel() ?? '-', 'exists' => $media !== null, ], 'journalists' => [ 'count' => $journalists->count(), 'names' => $journalists->pluck('name')->take(3)->toArray(), 'exists' => $journalists->count() > 0, ], ]; } /** * Get alert data for verification status */ 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' => 'Verifikasi lengkap Anda telah diterima dan disetujui oleh admin. Seluruh data (Perusahaan, Media, dan Jurnalis) telah terverifikasi.', '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 */ public function getMissingDataButtons(?Company $company): array { $buttons = []; if (! $company) { $buttons[] = [ 'label' => 'Lengkapi Data Perusahaan', 'url' => PagesCompany::getUrl(), 'icon' => 'building-office-2', 'color' => 'warning', ]; } if ($company && ! $company->partnerMedia) { $buttons[] = [ 'label' => 'Lengkapi Data Media', 'url' => Media::getUrl(), 'icon' => 'newspaper', 'color' => 'warning', ]; } if ($company && $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; } }