pending()->count(); } public function getVerifications(): LengthAwarePaginator { $query = VerificationRequest::with([ 'company.user', 'company.partnerMedia', 'company.partnerMedia.journalists', 'submittedBy', 'reviews.reviewer', ]) ->latest('updated_at'); // Apply status filter if ($this->filterStatus !== 'all') { $query->where('status', $this->filterStatus); } return $query->paginate(12); } public function setFilter(string $status): void { $this->filterStatus = $status; } public function getStatusCounts(): array { return [ 'all' => VerificationRequest::count(), 'pending' => VerificationRequest::pending()->count(), 'revision' => VerificationRequest::needRevision()->count(), 'approved' => VerificationRequest::approved()->count(), 'rejected' => VerificationRequest::rejected()->count(), ]; } /** * Get company name from verification request */ public function getCompanyName(VerificationRequest $request): string { return $request->company?->name ?? 'Data tidak ditemukan'; } /** * Get detail URL for the company */ public function getDetailUrl(VerificationRequest $request): ?string { if (! $request->company || ! $request->company->user_id) { return null; } return ViewPartner::getUrl(['record' => $request->company->user_id]); } /** * Get verification summary data */ 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 card data for verification request */ public function getCardData(VerificationRequest $verification): array { $latestReview = $verification->reviews->first(); $summary = $this->getVerificationSummary($verification); $status = $verification->status; return [ 'companyName' => $this->getCompanyName($verification), 'detailUrl' => $this->getDetailUrl($verification), 'status' => $status, 'statusLabel' => $status->getLabel(), 'statusColor' => $status->getColor(), 'summary' => $summary, 'latestReview' => $latestReview, 'latestReviewNote' => $latestReview?->note, 'latestReviewDecision' => $latestReview?->decision, 'latestReviewDecisionLabel' => $latestReview?->decision?->getLabel(), 'latestReviewDecisionColor' => $latestReview?->decision?->getColor(), 'latestReviewReviewer' => $latestReview?->reviewer?->name ?? 'Admin', 'latestReviewCreatedAt' => $latestReview?->created_at, 'submittedBy' => $verification->submittedBy?->name ?? 'Unknown', 'reviewsCount' => $verification->reviews->count(), 'canApprove' => $status === VerificationStatus::PENDING, 'isPending' => $status === VerificationStatus::PENDING, 'isRevision' => $status === VerificationStatus::NEED_REVISION, 'isApproved' => $status === VerificationStatus::APPROVED, 'isRejected' => $status === VerificationStatus::REJECTED, ]; } /** * Approve verification action */ public function approveAction(): Action { return Action::make('approve') ->label('Setujui') ->color('success') ->icon('heroicon-o-check') ->size('sm') ->requiresConfirmation() ->modalHeading('Setujui Verifikasi') ->modalDescription('Apakah Anda yakin ingin menyetujui verifikasi ini? Pastikan data sudah benar dan lengkap.') ->modalSubmitActionLabel('Ya, Setujui') ->action(function (array $arguments, array $data): void { $this->processReview($arguments['id'], DecisionAdmin::APPROVED, $data['note'] ?? null); }); } /** * Revision verification action */ public function revisionAction(): Action { return Action::make('revision') ->label('Minta Revisi') ->color('warning') ->icon('heroicon-o-pencil-square') ->size('sm') ->modalHeading('Minta Revisi') ->modalDescription('Pengguna akan diminta untuk memperbaiki data sesuai catatan yang diberikan.') ->schema([ Textarea::make('note') ->label('Catatan Revisi') ->required() ->placeholder('Jelaskan bagian yang perlu diperbaiki...') ->autocomplete(false) ->autofocus(), ]) ->action(function (array $arguments, array $data): void { $this->processReview($arguments['id'], DecisionAdmin::NEED_REVISION, $data['note']); }) ->modalWidth(Width::Large); } /** * Reject verification action */ public function rejectAction(): Action { return Action::make('reject') ->label('Tolak') ->color('danger') ->icon('heroicon-o-x-mark') ->size('sm') ->requiresConfirmation() ->modalHeading('Tolak Verifikasi') ->modalDescription('Pengajuan akan ditolak secara permanen. Pengguna tidak dapat mengajukan ulang untuk data ini.') ->modalSubmitActionLabel('Ya, Tolak') ->schema([ Textarea::make('note') ->label('Alasan Penolakan') ->required() ->placeholder('Jelaskan alasan pengajuan ditolak...') ->autocomplete(false) ->autofocus(), ]) ->action(function (array $arguments, array $data): void { $this->processReview($arguments['id'], DecisionAdmin::REJECTED, $data['note']); }); } /** * Process review decision */ protected function processReview(int $requestId, DecisionAdmin $decision, ?string $note): void { $verificationRequest = VerificationRequest::with(['company.partnerMedia.journalists'])->find($requestId); if (! $verificationRequest) { CheerfulNotification::danger( 'Belum ketemu nih 🙌', 'Data verifikasi belum kami temukan. Coba sebentar lagi, ya.', ) ->send(); return; } try { DB::beginTransaction(); // 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, ]); DB::commit(); $actionLabel = match ($decision) { DecisionAdmin::APPROVED => 'disetujui', DecisionAdmin::NEED_REVISION => 'diminta revisi', DecisionAdmin::REJECTED => 'ditolak', }; CheerfulNotification::success( 'Berhasil Diproses! ✨', "Mantap! Verifikasi telah {$actionLabel} dan notifikasi sudah dikirim ke pengguna. Kerja bagus, Admin! 💪" ) ->send(); // Notify User $partnerUser = $verificationRequest->company?->user; if ($partnerUser) { $statusTitle = match ($decision) { DecisionAdmin::APPROVED => 'Horee! Verifikasi Disetujui 🎉', DecisionAdmin::NEED_REVISION => 'Yah, Ada Yang Perlu Direvisi nih 📝', DecisionAdmin::REJECTED => 'Maaf, Verifikasi Ditolak 😔', }; $body = match ($decision) { DecisionAdmin::APPROVED => 'Yeay! Pengajuan verifikasi perusahaan Anda telah disetujui. Sekarang Anda sudah resmi terverifikasi dan bekerja sama dengan kami! 🎊', DecisionAdmin::NEED_REVISION => 'Ayo sedikit lagi! Admin meminta beberapa perbaikan pada pengajuan Anda agar bisa segera disetujui. 💪', DecisionAdmin::REJECTED => 'Yah, maaf banget... pengajuan verifikasi perusahaan Anda belum bisa kami terima saat ini. 💔', }; if ($note) { $body .= "\n\nCatatan Admin: {$note}"; } $partnerUser->notify(new BroadcastNotification([ 'title' => $statusTitle, 'body' => $body, 'action' => [ Action::make('view') ->label('Lihat') ->url(Verification::getUrl()), ], ])); } } catch (\Throwable $e) { DB::rollBack(); Log::error('Verification processing failed', [ 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), 'request_id' => $requestId, 'decision' => $decision->value, ]); CheerfulNotification::danger( 'Terjadi Kesalahan ⚠️', 'Proses verifikasi gagal karena kesalahan sistem. Tim kami sudah mencatat masalah ini. Silakan coba lagi nanti.', ) ->send(); } } }