$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() === 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()), ]; } }