sispace/app/Filament/Resources/Learning/Assignments/Pages/SubmissionDetailPage.php

216 lines
8.6 KiB
PHP

<?php
namespace App\Filament\Resources\Learning\Assignments\Pages;
use App\Enums\AssignmentType;
use App\Filament\Actions\BackAction;
use App\Filament\Resources\Learning\Assignments\Actions\MarkAsSentAction;
use App\Filament\Resources\Learning\Assignments\AssignmentResource;
use App\Filament\Support\SystemNotification;
use App\Models\Assignment;
use App\Models\AssignmentSubmission;
use Filament\Actions\Action;
use Filament\Resources\Pages\Page;
use Filament\Support\Enums\Width;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Joaopaulolndev\FilamentPdfViewer\Infolists\Components\PdfViewerEntry;
use Livewire\Attributes\Computed;
class SubmissionDetailPage extends Page
{
protected static string $resource = AssignmentResource::class;
protected string $view = 'filament.resources.learning.assignments.submission-detail';
protected static ?string $title = 'Detail Rekap Pengumpulan';
public Assignment $record;
#[Computed]
public function statCards(): array
{
return [
[
'label' => $this->record?->type === AssignmentType::Individual ? 'Total Mahasiswa' : 'Total Kelompok',
'value' => $this->totalCount,
'icon' => 'heroicon-o-user-group',
'color_classes' => 'bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-900',
],
[
'label' => 'Sudah Kumpul',
'value' => $this->doneCount,
'icon' => 'heroicon-o-check-circle',
'color_classes' => 'bg-success-100 dark:bg-success-900/30 text-success-700 dark:text-success-400',
],
[
'label' => 'Belum Kumpul',
'value' => $this->totalCount - $this->doneCount,
'icon' => 'heroicon-o-x-circle',
'color_classes' => 'bg-danger-100 dark:bg-danger-900/30 text-danger-700 dark:text-danger-400',
],
[
'label' => 'Persentase',
'value' => $this->percentage.'%',
'icon' => 'heroicon-o-chart-bar',
'color_classes' => 'bg-primary-100 dark:bg-primary-900/30 text-primary-700 dark:text-primary-400',
],
[
'label' => 'Status Dosen',
'value' => $this->record?->is_sent_to_lecturer ? 'SUDAH TERKIRIM' : 'BELUM TERKIRIM',
'icon' => $this->record?->is_sent_to_lecturer ? 'heroicon-o-check-badge' : 'heroicon-o-clock',
'color_classes' => $this->record?->is_sent_to_lecturer
? 'bg-success-500 text-white shadow-lg shadow-success-200 dark:shadow-none'
: 'bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-400',
],
];
}
#[Computed]
public function progressColorClass(): string
{
return $this->percentage === 100 ? 'bg-success-500' : ($this->percentage > 0 ? 'bg-warning-500' : 'bg-gray-300');
}
#[Computed]
public function submissionSummary(): Collection
{
$assignment = $this->record?->load(['students', 'studyGroups', 'course']);
$isIndividual = $assignment->type === AssignmentType::Individual;
if ($isIndividual) {
$targets = $assignment->students?->keyBy('id') ?? collect();
$submissions = AssignmentSubmission::with('student')
->where('assignment_id', $assignment->id)
->get()
->keyBy('student_id');
return $targets->map(function ($student) use ($submissions) {
$submission = $submissions->get($student->id);
$isSubmitted = $submission !== null;
return (object) [
'id' => $student->id,
'is_individual' => true,
'primary_name' => $student->full_name,
'secondary_info' => $student->student_number,
'submission_id' => $submission?->id,
'submitted' => $isSubmitted,
'submitted_at_formatted' => $isSubmitted ? $submission?->submitted_at?->translatedFormat('l, d F Y H:i') : '-',
'has_file' => $isSubmitted && $submission->hasMedia('submission'),
'status_classes' => Arr::toCssClasses([
'inline-flex items-center gap-1 rounded-full px-2.5 py-0.5 text-xs font-medium',
'bg-success-100 text-success-700 dark:bg-success-900/30 dark:text-success-400' => $isSubmitted,
'bg-danger-100 text-danger-700 dark:bg-danger-900/30 dark:text-danger-400' => ! $isSubmitted,
]),
'status_label' => $isSubmitted ? '✓ Terkumpul' : 'Belum',
];
})->sortBy('secondary_info')->values();
} else {
$targets = $assignment->studyGroups?->keyBy('id') ?? collect();
$submissions = AssignmentSubmission::with(['studyGroup', 'student'])
->where('assignment_id', $assignment->id)
->get()
->keyBy('study_group_id');
return $targets->map(function ($group) use ($submissions) {
$submission = $submissions->get($group->id);
$isSubmitted = $submission !== null;
return (object) [
'id' => $group->id,
'is_individual' => false,
'primary_name' => $group->name,
'secondary_info' => $isSubmitted ? $submission?->student?->full_name : '-',
'submission_id' => $submission?->id,
'submitted' => $isSubmitted,
'submitted_at_formatted' => $isSubmitted ? $submission->submitted_at?->translatedFormat('l, d F Y H:i') : '-',
'has_file' => $isSubmitted && $submission->hasMedia('submission'),
'status_classes' => Arr::toCssClasses([
'inline-flex items-center gap-1 rounded-full px-2.5 py-0.5 text-xs font-medium',
'bg-success-100 text-success-700 dark:bg-success-900/30 dark:text-success-400' => $isSubmitted,
'bg-danger-100 text-danger-700 dark:bg-danger-900/30 dark:text-danger-400' => ! $isSubmitted,
]),
'status_label' => $isSubmitted ? '✓ Terkumpul' : 'Belum',
];
})->sortBy('primary_name')->values();
}
}
#[Computed]
public function totalCount(): int
{
return $this->submissionSummary?->count();
}
#[Computed]
public function doneCount(): int
{
return $this->submissionSummary?->where('submitted', true)->count();
}
#[Computed]
public function percentage(): int
{
$total = $this->totalCount;
return $total > 0 ? (int) round(($this->doneCount / $total) * 100) : 0;
}
#[Computed]
public function isOverdue(): bool
{
return now()->isAfter($this->record?->due_date);
}
#[Computed]
public function assignmentSummary(): array
{
return [
'title' => $this->record?->title,
'course' => $this->record?->course?->name ?? '-',
'due_date' => $this->record?->due_date?->translatedFormat('l, d F Y H:i'),
'type' => $this->record?->type->value,
'is_overdue' => $this->isOverdue,
'is_sent_to_lecturer' => $this->record?->is_sent_to_lecturer,
];
}
#[Computed]
public function sectionIcon(): string
{
return SystemNotification::getNotifStyle() === \App\Enums\NotifStyle::Cheerful
? 'heroicon-o-document-magnifying-glass'
: 'heroicon-o-document-text';
}
public function previewSubmissionAction(): Action
{
return Action::make('previewSubmission')
->record(fn (array $arguments) => AssignmentSubmission::find($arguments['submissionId']))
->modalHeading('File Tugas')
->modalWidth(Width::SixExtraLarge)
->infolist([
PdfViewerEntry::make('submission')
->hiddenLabel()
->fileUrl(fn (AssignmentSubmission $record) => $record->getFirstMediaUrl('submission'))
->columnSpanFull(),
])
->modalSubmitAction(false)
->modalCancelActionLabel('Tutup');
}
protected function getHeaderActions(): array
{
return [
MarkAsSentAction::make()
->record($this->record),
BackAction::make()
->url(AssignmentResource::getUrl()),
];
}
}