simedkom/app/Filament/Resources/Manage/Cooperations/Pages/ViewCooperation.php
Yoga Pangestu 6fe5e81717 refactor: add type hinting to closures and fix logic errors in Filament codebase
- Added comprehensive parameter and return type hinting to closures across various Filament resources, actions, and relation managers to improve type safety and static analysis.
- Fixed logic in ReportRelationManager where report count was incorrectly compared, preventing the 'Buat Laporan' button from showing correctly.
- Corrected namespaces for RepeatableEntry and TextEntry in ViewCooperation (changed from Filament\Schemas to Filament\Infolists).
- Fixed component rendering in JournalistResource form by ensuring sections are correctly returned in the mapping.
- Added @var docblocks to resolve lint errors related to auth()->user() and verified query builder return types.
- Standardized file retrieval logic in PartnerResource and improved overall code reliability."
2026-01-12 15:17:21 +07:00

322 lines
10 KiB
PHP

<?php
namespace App\Filament\Resources\Manage\Cooperations\Pages;
use App\Enums\ApprovalStatus;
use App\Filament\Resources\Manage\Cooperations\CooperationResource;
use Filament\Actions\Action;
use Filament\Infolists\Components\RepeatableEntry;
use Filament\Infolists\Components\TextEntry;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\ViewRecord;
use Filament\Support\Enums\FontWeight;
use Illuminate\Support\Facades\Auth;
class ViewCooperation extends ViewRecord
{
protected static string $resource = CooperationResource::class;
protected function getWorkflowSteps()
{
$record = $this->getRecord();
$steps = [
[
'step' => 1,
'title' => 'Pengajuan Kerja Sama',
'description' => 'Admin mengajukan kerja sama ke media',
'status' => 'completed', // Always completed since we're viewing it
'date' => $record->created_at?->format('d/m/Y H:i'),
],
[
'step' => 2,
'title' => 'Respon Media',
'description' => 'Media menerima atau menolak pengajuan',
'status' => $this->getMediaResponseStatus($record),
'date' => $this->getMediaResponseDate($record),
],
[
'step' => 3,
'title' => 'Upload Proposal',
'description' => 'Media mengupload dokumen proposal',
'status' => $this->getProposalStatus($record),
'date' => $this->getProposalDate($record),
],
[
'step' => 4,
'title' => 'Review Proposal',
'description' => 'Admin mereview dan menyetujui proposal',
'status' => $this->getProposalReviewStatus($record),
'date' => $this->getProposalReviewDate($record),
],
[
'step' => 5,
'title' => 'Penugasan',
'description' => 'Admin membuat task assignment',
'status' => $this->getTaskStatus($record),
'date' => $this->getTaskDate($record),
],
[
'step' => 6,
'title' => 'Upload Laporan',
'description' => 'Media mengupload laporan',
'status' => $this->getReportStatus($record),
'date' => $this->getReportDate($record),
],
[
'step' => 7,
'title' => 'Selesai',
'description' => 'Kerja sama telah selesai',
'status' => $this->getCompletionStatus($record),
'date' => $this->getCompletionDate($record),
],
];
return RepeatableEntry::make('workflow_steps')
->label('')
->schema([
TextEntry::make('step')
->label('Langkah')
->formatStateUsing(fn (int $state): string => "Langkah {$state}")
->weight(FontWeight::Bold),
TextEntry::make('title')
->label('Judul'),
TextEntry::make('description')
->label('Deskripsi'),
TextEntry::make('status')
->label('Status')
->badge()
->color(fn (string $state): string => match ($state) {
'completed' => 'success',
'in_progress' => 'warning',
'pending' => 'gray',
'rejected' => 'danger',
default => 'gray',
})
->formatStateUsing(fn (string $state): string => match ($state) {
'completed' => 'Selesai',
'in_progress' => 'Sedang Berjalan',
'pending' => 'Menunggu',
'rejected' => 'Ditolak',
default => $state,
}),
TextEntry::make('date')
->label('Tanggal')
->placeholder('Belum ada'),
])
->columns(5)
->state($steps);
}
protected function getMediaResponseStatus($record): string
{
$mediaStatuses = $record->cooperationMedia->pluck('status')->unique();
if ($mediaStatuses->contains(ApprovalStatus::ACCEPTED)) {
return 'completed';
}
if ($mediaStatuses->contains(ApprovalStatus::REJECTED)) {
return 'rejected';
}
return 'pending';
}
protected function getMediaResponseDate($record)
{
$latestResponse = $record->cooperationMedia
->whereNotNull('updated_at')
->sortByDesc('updated_at')
->first();
return $latestResponse?->updated_at?->format('d/m/Y H:i');
}
protected function getProposalStatus($record): string
{
if ($record->proposals()->exists()) {
return 'completed';
}
return 'pending';
}
protected function getProposalDate($record)
{
$latestProposal = $record->proposals->sortByDesc('created_at')->first();
return $latestProposal?->created_at?->format('d/m/Y H:i');
}
protected function getProposalReviewStatus($record): string
{
$proposals = $record->proposals;
if ($record->proposals()->accepted()->exists()) {
return 'completed';
}
if ($record->proposals()->rejected()->exists()) {
return 'rejected';
}
if ($proposals->isNotEmpty()) {
return 'in_progress';
}
return 'pending';
}
protected function getProposalReviewDate($record)
{
$latestProposal = $record->proposals->sortByDesc('updated_at')->first();
return $latestProposal?->updated_at?->format('d/m/Y H:i');
}
protected function getTaskStatus($record): string
{
if ($record->taskAssignments->isNotEmpty()) {
return 'completed';
}
return 'pending';
}
protected function getTaskDate($record)
{
$latestTask = $record->taskAssignments->sortByDesc('created_at')->first();
return $latestTask?->created_at?->format('d/m/Y H:i');
}
protected function getReportStatus($record): string
{
$tasks = $record->taskAssignments;
if ($tasks->isEmpty()) {
return 'pending';
}
$totalReports = $tasks->sum('report_amount');
$completedReports = $tasks->flatMap->reports->count();
if ($completedReports >= $totalReports && $totalReports > 0) {
return 'completed';
}
if ($completedReports > 0) {
return 'in_progress';
}
return 'pending';
}
protected function getReportDate($record)
{
$latestReport = $record->taskAssignments
->flatMap->reports
->sortByDesc('created_at')
->first();
return $latestReport?->created_at?->format('d/m/Y H:i');
}
protected function getCompletionStatus($record): string
{
// Logic for completion - could be based on all reports accepted, etc.
return 'pending';
}
protected function getCompletionDate($record)
{
return null;
}
protected function getHeaderActions(): array
{
$isPerusahaan = Auth::user()->hasRole('Perusahaan');
$record = $this->getRecord();
$actions = [];
if (! $isPerusahaan) {
$actions[] = Action::make('mark_completed')
->label('Tandai Selesai')
->icon('heroicon-o-check-circle')
->color('success')
->action(function (): void {
// Logic to mark cooperation as completed
Notification::make()
->title('Kerja Sama Ditandai Selesai')
->success()
->send();
})
->visible(fn (): bool => $this->canMarkAsCompleted());
} else {
// For Perusahaan users, add accept/reject actions if they have a cooperation media record
$cooperationMedia = $record->cooperationMedia()
->whereHas('partnerMedia', function (\Illuminate\Database\Eloquent\Builder $query): void {
$query->whereHas('company', function (\Illuminate\Database\Eloquent\Builder $subQuery): void {
$subQuery->where('user_id', Auth::id());
});
})
->first();
if ($cooperationMedia && $cooperationMedia->status === ApprovalStatus::PENDING) {
$actions[] = Action::make('accept')
->label('Terima Kerja Sama')
->icon('heroicon-o-check-circle')
->color('success')
->action(function () use ($cooperationMedia): void {
$cooperationMedia->update(['status' => ApprovalStatus::ACCEPTED]);
Notification::make()
->title('Kerja Sama Diterima')
->success()
->send();
});
$actions[] = Action::make('reject')
->label('Tolak Kerja Sama')
->icon('heroicon-o-x-circle')
->color('danger')
->action(function () use ($cooperationMedia): void {
$cooperationMedia->update(['status' => ApprovalStatus::REJECTED]);
Notification::make()
->title('Kerja Sama Ditolak')
->success()
->send();
});
}
}
$actions[] = Action::make('back')
->label('Kembali')
->url(fn (): string => static::getResource()::getUrl('index'))
->outlined()
->color('secondary');
return $actions;
}
protected function canMarkAsCompleted(): bool
{
$record = $this->getRecord();
// Check if all tasks have required number of reports
foreach ($record->taskAssignments as $task) {
$reportCount = $task->reports()->count();
if ($reportCount < $task->report_amount) {
return false;
}
}
return $record->taskAssignments->isNotEmpty();
}
}