feat: add download support for non-PDF files in assignment submission views
This commit is contained in:
parent
9727e8d52f
commit
1f0db96179
@ -11,6 +11,7 @@
|
|||||||
use App\Models\Assignment;
|
use App\Models\Assignment;
|
||||||
use App\Models\AssignmentSubmission;
|
use App\Models\AssignmentSubmission;
|
||||||
use Filament\Actions\Action;
|
use Filament\Actions\Action;
|
||||||
|
use Filament\Infolists\Components\TextEntry;
|
||||||
use Filament\Resources\Pages\Page;
|
use Filament\Resources\Pages\Page;
|
||||||
use Filament\Support\Enums\Width;
|
use Filament\Support\Enums\Width;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
@ -100,6 +101,8 @@ public function submissionSummary(): Collection
|
|||||||
'submitted' => $isSubmitted,
|
'submitted' => $isSubmitted,
|
||||||
'submitted_at_formatted' => $isSubmitted ? $submission?->submitted_at?->translatedFormat('l, d F Y H:i') : '-',
|
'submitted_at_formatted' => $isSubmitted ? $submission?->submitted_at?->translatedFormat('l, d F Y H:i') : '-',
|
||||||
'has_file' => $isSubmitted && $submission->hasMedia('submission'),
|
'has_file' => $isSubmitted && $submission->hasMedia('submission'),
|
||||||
|
'is_pdf' => $isSubmitted && str_ends_with(strtolower($submission->getFirstMediaUrl('submission')), '.pdf'),
|
||||||
|
'file_url' => $isSubmitted ? $submission->getFirstMediaUrl('submission') : null,
|
||||||
'status_classes' => Arr::toCssClasses([
|
'status_classes' => Arr::toCssClasses([
|
||||||
'inline-flex items-center gap-1 rounded-full px-2.5 py-0.5 text-xs font-medium',
|
'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-success-100 text-success-700 dark:bg-success-900/30 dark:text-success-400' => $isSubmitted,
|
||||||
@ -129,6 +132,8 @@ public function submissionSummary(): Collection
|
|||||||
'submitted' => $isSubmitted,
|
'submitted' => $isSubmitted,
|
||||||
'submitted_at_formatted' => $isSubmitted ? $submission->submitted_at?->translatedFormat('l, d F Y H:i') : '-',
|
'submitted_at_formatted' => $isSubmitted ? $submission->submitted_at?->translatedFormat('l, d F Y H:i') : '-',
|
||||||
'has_file' => $isSubmitted && $submission->hasMedia('submission'),
|
'has_file' => $isSubmitted && $submission->hasMedia('submission'),
|
||||||
|
'is_pdf' => $isSubmitted && str_ends_with(strtolower($submission->getFirstMediaUrl('submission')), '.pdf'),
|
||||||
|
'file_url' => $isSubmitted ? $submission->getFirstMediaUrl('submission') : null,
|
||||||
'status_classes' => Arr::toCssClasses([
|
'status_classes' => Arr::toCssClasses([
|
||||||
'inline-flex items-center gap-1 rounded-full px-2.5 py-0.5 text-xs font-medium',
|
'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-success-100 text-success-700 dark:bg-success-900/30 dark:text-success-400' => $isSubmitted,
|
||||||
@ -195,14 +200,39 @@ public function previewSubmissionAction(): Action
|
|||||||
->modalWidth(Width::SixExtraLarge)
|
->modalWidth(Width::SixExtraLarge)
|
||||||
->infolist([
|
->infolist([
|
||||||
PdfViewerEntry::make('submission')
|
PdfViewerEntry::make('submission')
|
||||||
|
->visible(fn (AssignmentSubmission $record) => str_ends_with(strtolower($record->getFirstMediaUrl('submission')), '.pdf'))
|
||||||
->hiddenLabel()
|
->hiddenLabel()
|
||||||
->fileUrl(fn (AssignmentSubmission $record) => $record->getFirstMediaUrl('submission'))
|
->fileUrl(fn (AssignmentSubmission $record) => $record->getFirstMediaUrl('submission'))
|
||||||
->columnSpanFull(),
|
->columnSpanFull(),
|
||||||
|
|
||||||
|
TextEntry::make('download_file')
|
||||||
|
->label('Berkas non-PDF')
|
||||||
|
->visible(fn (AssignmentSubmission $record) => ! str_ends_with(strtolower($record->getFirstMediaUrl('submission')), '.pdf'))
|
||||||
|
->hint('Klik ikon unduh untuk melihat isi berkas.')
|
||||||
|
->default(fn (AssignmentSubmission $record) => $record->getFirstMedia('submission')?->file_name ?? 'Unduh Berkas')
|
||||||
|
->suffixAction(
|
||||||
|
Action::make('download')
|
||||||
|
->label('Unduh')
|
||||||
|
->icon('heroicon-o-arrow-down-tray')
|
||||||
|
->url(fn (AssignmentSubmission $record) => $record->getFirstMediaUrl('submission'), true)
|
||||||
|
),
|
||||||
])
|
])
|
||||||
->modalSubmitAction(false)
|
->modalSubmitAction(false)
|
||||||
->modalCancelActionLabel('Tutup');
|
->modalCancelActionLabel('Tutup');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function downloadMedia(int $submissionId)
|
||||||
|
{
|
||||||
|
$submission = AssignmentSubmission::findOrFail($submissionId);
|
||||||
|
$media = $submission->getFirstMedia('submission');
|
||||||
|
|
||||||
|
if (! $media) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->download($media->getPath(), $media->file_name);
|
||||||
|
}
|
||||||
|
|
||||||
protected function getHeaderActions(): array
|
protected function getHeaderActions(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
|||||||
@ -248,6 +248,26 @@ public function getSubmissionFileUrl(): ?string
|
|||||||
return $this->existingSubmission?->getFirstMediaUrl('submission');
|
return $this->existingSubmission?->getFirstMediaUrl('submission');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function downloadAttachment()
|
||||||
|
{
|
||||||
|
$media = $this->record->getFirstMedia('assignments');
|
||||||
|
if (! $media) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->download($media->getPath(), $media->file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function downloadSubmission()
|
||||||
|
{
|
||||||
|
$media = $this->existingSubmission?->getFirstMedia('submission');
|
||||||
|
if (! $media) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->download($media->getPath(), $media->file_name);
|
||||||
|
}
|
||||||
|
|
||||||
public function submit(): void
|
public function submit(): void
|
||||||
{
|
{
|
||||||
$student = $this->student;
|
$student = $this->student;
|
||||||
|
|||||||
@ -111,7 +111,7 @@ public static function configure(Schema $schema): Schema
|
|||||||
->columnSpanFull(),
|
->columnSpanFull(),
|
||||||
|
|
||||||
AdvancedFileUpload::make('pdf')
|
AdvancedFileUpload::make('pdf')
|
||||||
->label('Lampiran PDF')
|
->label('Lampiran Berkas')
|
||||||
->pdfPreviewHeight(400)
|
->pdfPreviewHeight(400)
|
||||||
->pdfDisplayPage(1)
|
->pdfDisplayPage(1)
|
||||||
->pdfToolbar(true)
|
->pdfToolbar(true)
|
||||||
@ -119,7 +119,7 @@ public static function configure(Schema $schema): Schema
|
|||||||
->pdfFitType(PdfViewFit::FIT)
|
->pdfFitType(PdfViewFit::FIT)
|
||||||
->pdfNavPanes(true)
|
->pdfNavPanes(true)
|
||||||
->disk(config('filesystems.default'))
|
->disk(config('filesystems.default'))
|
||||||
->acceptedFileTypes(['application/pdf'])
|
->acceptedFileTypes(['application/pdf', 'application/zip', 'application/x-zip-compressed', 'application/x-zip', 'application/octet-stream', 'multipart/x-zip', '.zip', '.7z'])
|
||||||
->maxSize(1024 * 5)
|
->maxSize(1024 * 5)
|
||||||
->directory('assignments-tmp/'.now()->toDateString())
|
->directory('assignments-tmp/'.now()->toDateString())
|
||||||
->nullable()
|
->nullable()
|
||||||
|
|||||||
@ -13,7 +13,7 @@ public static function configure(Schema $schema): Schema
|
|||||||
return $schema
|
return $schema
|
||||||
->components([
|
->components([
|
||||||
AdvancedFileUpload::make('file')
|
AdvancedFileUpload::make('file')
|
||||||
->label(fn ($get) => $get('is_resubmit') ? 'Ganti Berkas PDF (Opsional)' : 'Lampiran Berkas Tugas')
|
->label(fn ($get) => $get('is_resubmit') ? 'Ganti Berkas Tugas (Opsional)' : 'Lampiran Berkas Tugas')
|
||||||
->pdfPreviewHeight(400)
|
->pdfPreviewHeight(400)
|
||||||
->pdfDisplayPage(1)
|
->pdfDisplayPage(1)
|
||||||
->pdfToolbar(true)
|
->pdfToolbar(true)
|
||||||
@ -21,12 +21,12 @@ public static function configure(Schema $schema): Schema
|
|||||||
->pdfFitType(PdfViewFit::FIT)
|
->pdfFitType(PdfViewFit::FIT)
|
||||||
->pdfNavPanes(true)
|
->pdfNavPanes(true)
|
||||||
->disk(config('filesystems.default'))
|
->disk(config('filesystems.default'))
|
||||||
->acceptedFileTypes(['application/pdf'])
|
->acceptedFileTypes(['application/pdf', 'application/zip', 'application/x-zip-compressed', 'application/x-zip', 'application/octet-stream', 'multipart/x-zip', '.zip', '.7z'])
|
||||||
->maxSize(1024 * 5)
|
->maxSize(1024 * 5)
|
||||||
->directory('submissions/'.now()->toDateString())
|
->directory('submissions/'.now()->toDateString())
|
||||||
->required(fn ($get) => ! $get('is_resubmit'))
|
->required(fn ($get) => ! $get('is_resubmit'))
|
||||||
->hiddenLabel()
|
->hiddenLabel()
|
||||||
->helperText('Hanya file PDF dengan ukuran maksimal 5MB.')
|
->helperText('File PDF atau ZIP dengan ukuran maksimal 5MB.')
|
||||||
->columnSpanFull(),
|
->columnSpanFull(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -101,12 +101,21 @@
|
|||||||
|
|
||||||
<td class="px-4 py-3">
|
<td class="px-4 py-3">
|
||||||
@if ($item->has_file)
|
@if ($item->has_file)
|
||||||
<button type="button"
|
@if ($item->is_pdf)
|
||||||
wire:click="mountAction('previewSubmission', { submissionId: {{ $item->submission_id }} })"
|
<button type="button"
|
||||||
class="inline-flex items-center gap-1 text-xs text-primary-600 dark:text-primary-400 hover:underline">
|
wire:click="mountAction('previewSubmission', { submissionId: {{ $item->submission_id }} })"
|
||||||
<x-filament::icon icon="heroicon-o-eye" class="h-3.5 w-3.5" />
|
class="inline-flex items-center gap-1 text-xs text-primary-600 dark:text-primary-400 hover:underline">
|
||||||
Lihat Tugas
|
<x-filament::icon icon="heroicon-o-eye" class="h-3.5 w-3.5" />
|
||||||
</button>
|
Lihat Tugas
|
||||||
|
</button>
|
||||||
|
@else
|
||||||
|
<button type="button"
|
||||||
|
wire:click="downloadMedia({{ $item->submission_id }})"
|
||||||
|
class="inline-flex items-center gap-1 text-xs text-success-600 dark:text-success-400 hover:underline">
|
||||||
|
<x-filament::icon icon="heroicon-o-arrow-down-tray" class="h-3.5 w-3.5" />
|
||||||
|
Unduh ZIP
|
||||||
|
</button>
|
||||||
|
@endif
|
||||||
@else
|
@else
|
||||||
<span class="text-xs text-gray-400">-</span>
|
<span class="text-xs text-gray-400">-</span>
|
||||||
@endif
|
@endif
|
||||||
|
|||||||
@ -35,11 +35,28 @@ class="prose prose-sm dark:prose-invert max-w-none text-gray-600 dark:text-gray-
|
|||||||
@if ($attachmentUrl = $this->record->getFirstMediaUrl('assignments'))
|
@if ($attachmentUrl = $this->record->getFirstMediaUrl('assignments'))
|
||||||
<div class="mt-4 pt-4 border-t border-gray-100 dark:border-gray-700">
|
<div class="mt-4 pt-4 border-t border-gray-100 dark:border-gray-700">
|
||||||
<p class="text-xs font-medium text-gray-500 dark:text-gray-400 mb-2">Lampiran Tugas</p>
|
<p class="text-xs font-medium text-gray-500 dark:text-gray-400 mb-2">Lampiran Tugas</p>
|
||||||
<div
|
@if (str_ends_with(strtolower($attachmentUrl), '.pdf'))
|
||||||
class="rounded-lg overflow-hidden border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900">
|
<div
|
||||||
<iframe src="{{ $attachmentUrl }}" width="100%" height="500"
|
class="rounded-lg overflow-hidden border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900">
|
||||||
class="block border-0"></iframe>
|
<iframe src="{{ $attachmentUrl }}" width="100%" height="500"
|
||||||
</div>
|
class="block border-0"></iframe>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-900 rounded-xl border border-gray-200 dark:border-gray-700 group hover:border-primary-500 transition-colors">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<div class="p-2.5 bg-primary-100 dark:bg-primary-900/30 rounded-lg text-primary-600">
|
||||||
|
<x-filament::icon icon="heroicon-o-document-arrow-down" class="w-6 h-6" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-sm font-semibold text-gray-900 dark:text-white">{{ $this->record->getFirstMedia('assignments')?->file_name ?? 'Berkas Lampiran' }}</p>
|
||||||
|
<p class="text-xs text-gray-500 dark:text-gray-400">Klik tombol di samping untuk mengunduh berkas.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<x-filament::button type="button" wire:click="downloadAttachment" color="gray" size="sm" icon="heroicon-o-arrow-down-tray">
|
||||||
|
Unduh
|
||||||
|
</x-filament::button>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</x-filament::section>
|
</x-filament::section>
|
||||||
@ -63,11 +80,28 @@ class="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-dange
|
|||||||
@if ($url = $this->getSubmissionFileUrl())
|
@if ($url = $this->getSubmissionFileUrl())
|
||||||
<div>
|
<div>
|
||||||
<p class="text-xs font-medium text-gray-500 dark:text-gray-400 mb-2">File yang Terakhir Dikumpulkan</p>
|
<p class="text-xs font-medium text-gray-500 dark:text-gray-400 mb-2">File yang Terakhir Dikumpulkan</p>
|
||||||
<div
|
@if (str_ends_with(strtolower($url), '.pdf'))
|
||||||
class="rounded-lg overflow-hidden border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900">
|
<div
|
||||||
<iframe src="{{ $url }}" width="100%" height="400"
|
class="rounded-lg overflow-hidden border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900">
|
||||||
class="block border-0"></iframe>
|
<iframe src="{{ $url }}" width="100%" height="400"
|
||||||
</div>
|
class="block border-0"></iframe>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-900 rounded-xl border border-gray-200 dark:border-gray-700 group hover:border-primary-500 transition-colors">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<div class="p-2.5 bg-primary-100 dark:bg-primary-900/30 rounded-lg text-primary-600">
|
||||||
|
<x-filament::icon icon="heroicon-o-document-arrow-down" class="w-6 h-6" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-sm font-semibold text-gray-900 dark:text-white">{{ $this->existingSubmission?->getFirstMedia('submission')?->file_name ?? 'Berkas Tugas' }}</p>
|
||||||
|
<p class="text-xs text-gray-500 dark:text-gray-400">Berkas non-PDF (ZIP)</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<x-filament::button type="button" wire:click="downloadSubmission" color="gray" size="sm" icon="heroicon-o-arrow-down-tray">
|
||||||
|
Unduh
|
||||||
|
</x-filament::button>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</x-filament::section>
|
</x-filament::section>
|
||||||
@ -86,11 +120,27 @@ class="flex flex-col items-center justify-center py-8 text-center text-gray-500
|
|||||||
<div class="mt-6">
|
<div class="mt-6">
|
||||||
<p class="text-xs font-medium text-gray-500 dark:text-gray-400 mb-2 italic">File yang telah
|
<p class="text-xs font-medium text-gray-500 dark:text-gray-400 mb-2 italic">File yang telah
|
||||||
dikumpulkan oleh kelompok Anda:</p>
|
dikumpulkan oleh kelompok Anda:</p>
|
||||||
<div
|
@if (str_ends_with(strtolower($url), '.pdf'))
|
||||||
class="rounded-lg overflow-hidden border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900">
|
<div
|
||||||
<iframe src="{{ $url }}" width="100%" height="400"
|
class="rounded-lg overflow-hidden border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900">
|
||||||
class="block border-0"></iframe>
|
<iframe src="{{ $url }}" width="100%" height="400"
|
||||||
</div>
|
class="block border-0"></iframe>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-900 rounded-xl border border-gray-200 dark:border-gray-700">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<div class="p-2.5 bg-primary-100 dark:bg-primary-900/30 rounded-lg text-primary-600">
|
||||||
|
<x-filament::icon icon="heroicon-o-document-arrow-down" class="w-6 h-6" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-sm font-semibold text-gray-900 dark:text-white">{{ $this->existingSubmission?->getFirstMedia('submission')?->file_name ?? 'Berkas Tugas' }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<x-filament::button type="button" wire:click="downloadSubmission" color="gray" size="sm" icon="heroicon-o-arrow-down-tray">
|
||||||
|
Unduh
|
||||||
|
</x-filament::button>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</x-filament::section>
|
</x-filament::section>
|
||||||
@ -112,11 +162,28 @@ class="block border-0"></iframe>
|
|||||||
@if ($this->isResubmit && ($url = $this->getSubmissionFileUrl()))
|
@if ($this->isResubmit && ($url = $this->getSubmissionFileUrl()))
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<p class="text-xs font-medium text-gray-500 dark:text-gray-400 mb-2">File Terkumpul Saat Ini</p>
|
<p class="text-xs font-medium text-gray-500 dark:text-gray-400 mb-2">File Terkumpul Saat Ini</p>
|
||||||
<div
|
@if (str_ends_with(strtolower($url), '.pdf'))
|
||||||
class="rounded-lg overflow-hidden border border-success-200 dark:border-success-800 bg-gray-50 dark:bg-gray-900">
|
<div
|
||||||
<iframe src="{{ $url }}" width="100%" height="400"
|
class="rounded-lg overflow-hidden border border-success-200 dark:border-success-800 bg-gray-50 dark:bg-gray-900">
|
||||||
class="block border-0"></iframe>
|
<iframe src="{{ $url }}" width="100%" height="400"
|
||||||
</div>
|
class="block border-0"></iframe>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<div class="flex items-center justify-between p-4 bg-success-50/50 dark:bg-success-900/10 rounded-xl border border-success-200 dark:border-success-800">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<div class="p-2.5 bg-success-100 dark:bg-success-900/30 rounded-lg text-success-600">
|
||||||
|
<x-filament::icon icon="heroicon-o-check-badge" class="w-6 h-6" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-sm font-semibold text-gray-900 dark:text-white">{{ $this->existingSubmission?->getFirstMedia('submission')?->file_name ?? 'Berkas Tugas' }}</p>
|
||||||
|
<p class="text-xs text-gray-500 dark:text-gray-400">Berkas Terkumpul (ZIP)</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<x-filament::button type="button" wire:click="downloadSubmission" color="success" size="sm" icon="heroicon-o-arrow-down-tray" variant="outline">
|
||||||
|
Unduh
|
||||||
|
</x-filament::button>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user