216 lines
8.6 KiB
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()),
|
|
];
|
|
}
|
|
}
|