feat: add class session materials and assignments viewing functionality, enhancing user experience with modals for detailed content display
This commit is contained in:
parent
5580ab5d55
commit
66c07556b7
@ -4,6 +4,7 @@
|
||||
|
||||
use App\Enums\AssignmentType;
|
||||
use App\Filament\Resources\Learning\Assignments\Actions\SelectAllStudentsAction;
|
||||
use App\Models\ClassSession;
|
||||
use App\Models\Course;
|
||||
use App\Models\Student;
|
||||
use App\Settings\GeneralSettings;
|
||||
@ -39,7 +40,7 @@ public static function configure(Schema $schema): Schema
|
||||
->autofocus()
|
||||
->columnSpanFull(),
|
||||
|
||||
Grid::make(3)
|
||||
Grid::make(2)
|
||||
->schema([
|
||||
Select::make('course_id')
|
||||
->label('Mata Kuliah')
|
||||
@ -53,6 +54,25 @@ public static function configure(Schema $schema): Schema
|
||||
->live()
|
||||
->required(),
|
||||
|
||||
Select::make('class_session_id')
|
||||
->label('Pertemuan Ke-')
|
||||
->placeholder('Pilih Pertemuan (Opsional)')
|
||||
->options(function (Get $get) {
|
||||
$courseId = $get('course_id');
|
||||
if (! $courseId) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return ClassSession::where('course_id', $courseId)
|
||||
->orderBy('session_number')
|
||||
->pluck('session_number', 'id')
|
||||
->map(fn ($num) => "Sesi Ke-$num")
|
||||
->toArray();
|
||||
})
|
||||
->searchable()
|
||||
->nullable()
|
||||
->helperText('Kosongkan jika tugas tidak terkait dengan sesi tertentu.'),
|
||||
|
||||
DateTimePicker::make('due_date')
|
||||
->label('Batas Waktu')
|
||||
->placeholder('Pilih Tanggal & Waktu')
|
||||
@ -70,6 +90,7 @@ public static function configure(Schema $schema): Schema
|
||||
->afterStateUpdated(function (Set $set) {
|
||||
$set('student_ids', []);
|
||||
$set('study_group_ids', []);
|
||||
$set('class_session_id', null);
|
||||
}),
|
||||
])
|
||||
->columnSpanFull(),
|
||||
|
||||
@ -185,7 +185,7 @@ public function generateSessionsAction(): Action
|
||||
});
|
||||
}
|
||||
|
||||
public function viewAttendanceAction(): Action
|
||||
protected function viewAttendanceAction(): Action
|
||||
{
|
||||
return Action::make('viewAttendance')
|
||||
->label('Lihat Presensi')
|
||||
@ -198,6 +198,32 @@ public function viewAttendanceAction(): Action
|
||||
]));
|
||||
}
|
||||
|
||||
protected function viewMaterialsAction(): Action
|
||||
{
|
||||
return Action::make('viewMaterials')
|
||||
->label('Daftar Materi')
|
||||
->modalHeading(fn (array $arguments) => 'Materi Kuliah - Sesi Ke-'.ClassSession::find($arguments['session'])->session_number)
|
||||
->modalSubmitAction(false)
|
||||
->modalCancelActionLabel('Tutup')
|
||||
->modalWidth(Width::Large)
|
||||
->modalContent(fn (array $arguments) => view('filament.resources.learning.class-sessions.materials-modal', [
|
||||
'materials' => ClassSession::find($arguments['session'])->materials()->latest()->get(),
|
||||
]));
|
||||
}
|
||||
|
||||
protected function viewAssignmentsAction(): Action
|
||||
{
|
||||
return Action::make('viewAssignments')
|
||||
->label('Daftar Tugas')
|
||||
->modalHeading(fn (array $arguments) => 'Tugas Kuliah - Sesi Ke-'.ClassSession::find($arguments['session'])->session_number)
|
||||
->modalSubmitAction(false)
|
||||
->modalCancelActionLabel('Tutup')
|
||||
->modalWidth(Width::Large)
|
||||
->modalContent(fn (array $arguments) => view('filament.resources.learning.class-sessions.assignments-modal', [
|
||||
'assignments' => ClassSession::find($arguments['session'])->assignments()->latest()->get(),
|
||||
]));
|
||||
}
|
||||
|
||||
public function editSessionAction(): Action
|
||||
{
|
||||
return EditAction::make('editSession')
|
||||
|
||||
@ -132,7 +132,7 @@ public function courses(): Collection
|
||||
});
|
||||
}
|
||||
|
||||
public function viewAttendanceAction(): Action
|
||||
protected function viewAttendanceAction(): Action
|
||||
{
|
||||
return Action::make('viewAttendance')
|
||||
->label('Lihat Presensi')
|
||||
@ -144,4 +144,30 @@ public function viewAttendanceAction(): Action
|
||||
'attendances' => ClassSession::find($arguments['session'])->attendances()->with('student')->latest('attended_at')->get(),
|
||||
]));
|
||||
}
|
||||
|
||||
protected function viewMaterialsAction(): Action
|
||||
{
|
||||
return Action::make('viewMaterials')
|
||||
->label('Daftar Materi')
|
||||
->modalHeading(fn (array $arguments) => 'Materi Kuliah - Sesi Ke-'.ClassSession::find($arguments['session'])->session_number)
|
||||
->modalSubmitAction(false)
|
||||
->modalCancelActionLabel('Tutup')
|
||||
->modalWidth(Width::Large)
|
||||
->modalContent(fn (array $arguments) => view('filament.resources.learning.class-sessions.materials-modal', [
|
||||
'materials' => ClassSession::find($arguments['session'])->materials()->latest()->get(),
|
||||
]));
|
||||
}
|
||||
|
||||
protected function viewAssignmentsAction(): Action
|
||||
{
|
||||
return Action::make('viewAssignments')
|
||||
->label('Daftar Tugas')
|
||||
->modalHeading(fn (array $arguments) => 'Tugas Kuliah - Sesi Ke-'.ClassSession::find($arguments['session'])->session_number)
|
||||
->modalSubmitAction(false)
|
||||
->modalCancelActionLabel('Tutup')
|
||||
->modalWidth(Width::Large)
|
||||
->modalContent(fn (array $arguments) => view('filament.resources.learning.class-sessions.assignments-modal', [
|
||||
'assignments' => ClassSession::find($arguments['session'])->assignments()->latest()->get(),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
use App\Filament\Actions\DefaultBulkActions;
|
||||
use App\Filament\Columns\TimestampColumns;
|
||||
use App\Filament\Resources\Learning\Materials\Pages\ManageMaterials;
|
||||
use App\Models\ClassSession;
|
||||
use App\Models\Course;
|
||||
use App\Models\Material;
|
||||
use App\Settings\GeneralSettings;
|
||||
@ -71,13 +72,24 @@ public static function form(Schema $schema): Schema
|
||||
->live()
|
||||
->required(),
|
||||
|
||||
DatePicker::make('published_at')
|
||||
->label('Tanggal Publikasi')
|
||||
->placeholder('Pilih Tanggal')
|
||||
->required()
|
||||
->native(false)
|
||||
->displayFormat('l, d F Y')
|
||||
->default(now()->toDateString()),
|
||||
Select::make('class_session_id')
|
||||
->label('Pertemuan Ke-')
|
||||
->placeholder('Pilih Pertemuan (Opsional)')
|
||||
->options(function ($get) {
|
||||
$courseId = $get('course_id');
|
||||
if (! $courseId) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return ClassSession::where('course_id', $courseId)
|
||||
->orderBy('session_number')
|
||||
->pluck('session_number', 'id')
|
||||
->map(fn ($num) => "Sesi Ke-$num")
|
||||
->toArray();
|
||||
})
|
||||
->searchable()
|
||||
->nullable()
|
||||
->helperText('Kosongkan jika materi tidak terkait dengan sesi tertentu.'),
|
||||
])
|
||||
->columnSpanFull(),
|
||||
|
||||
@ -128,15 +140,17 @@ public static function table(Table $table): Table
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('published_at')
|
||||
->label('Tanggal Publikasi')
|
||||
TextColumn::make('created_at')
|
||||
->label('Tanggal Dibuat')
|
||||
->date('l, d F Y')
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('description')
|
||||
->label('Deskripsi')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('classSession.session_number')
|
||||
->label('Pertemuan')
|
||||
->formatStateUsing(fn ($state) => $state ? "Sesi Ke-$state" : '-')
|
||||
->sortable()
|
||||
->badge()
|
||||
->color('gray'),
|
||||
|
||||
...TimestampColumns::make(),
|
||||
])
|
||||
@ -151,17 +165,17 @@ public static function table(Table $table): Table
|
||||
})
|
||||
->searchable(),
|
||||
|
||||
Filter::make('published_at')
|
||||
Filter::make('created_at')
|
||||
->schema([
|
||||
DatePicker::make('date')
|
||||
->label('Tanggal Publikasi')
|
||||
->label('Tanggal Dibuat')
|
||||
->placeholder('Pilih Tanggal')
|
||||
->native(false),
|
||||
])
|
||||
->query(function (Builder $query, array $data): Builder {
|
||||
return $query->when(
|
||||
$data['date'],
|
||||
fn (Builder $query, $date): Builder => $query->whereDate('published_at', $date),
|
||||
fn (Builder $query, $date): Builder => $query->whereDate('created_at', $date),
|
||||
);
|
||||
}),
|
||||
|
||||
|
||||
@ -15,10 +15,6 @@ class Material extends Model implements HasMedia
|
||||
|
||||
protected $guarded = ['id'];
|
||||
|
||||
protected $casts = [
|
||||
'published_at' => 'datetime',
|
||||
];
|
||||
|
||||
public function course(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Course::class);
|
||||
|
||||
@ -17,7 +17,6 @@ public function up(): void
|
||||
$table->foreignId('class_session_id')->nullable()->constrained()->nullOnDelete();
|
||||
$table->string('title', 100);
|
||||
$table->text('description')->nullable();
|
||||
$table->timestamp('published_at')->nullable();
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
$table->timestamp('updated_at')->nullable()->useCurrentOnUpdate();
|
||||
$table->softDeletes();
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
<div class="space-y-4 py-2">
|
||||
@forelse($assignments as $assignment)
|
||||
<div class="flex items-center justify-between p-3 rounded-lg border border-gray-100 dark:border-white/5 bg-gray-50/50 dark:bg-white/5 hover:bg-white dark:hover:bg-white/10 transition-colors shadow-sm">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="p-2 rounded-lg bg-primary-100 dark:bg-primary-900/20 text-primary-600 dark:text-primary-400">
|
||||
<x-heroicon-o-pencil-square class="w-5 h-5" />
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="font-bold text-gray-900 dark:text-white leading-tight uppercase font-mono text-[11px] mb-0.5 tracking-tight text-primary-600/60 dark:text-primary-400/50 block">
|
||||
{{ $assignment->type->label() ?? 'TUGAS' }}
|
||||
</span>
|
||||
<span class="font-bold text-gray-900 dark:text-white leading-tight">{{ $assignment->title }}</span>
|
||||
<div class="flex items-center gap-1.5 mt-0.5">
|
||||
<x-heroicon-o-clock class="w-3.5 h-3.5 text-gray-400 dark:text-gray-500" />
|
||||
<span class="text-[10px] text-gray-500 dark:text-gray-400 font-medium uppercase tracking-tight">
|
||||
Deadline: {{ $assignment->due_date?->translatedFormat('d F Y, H:i') ?? '-' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<a href="{{ \App\Filament\Resources\Learning\Assignments\AssignmentResource::getUrl('index') . '?tableFilters[course_id][value]=' . $assignment->course_id . '&tableSearch=' . urlencode($assignment->title) }}"
|
||||
class="p-1.5 rounded-full hover:bg-gray-200 dark:hover:bg-white/10 text-gray-500 transition-colors"
|
||||
title="Lihat Detail">
|
||||
<x-heroicon-o-chevron-right class="w-5 h-5" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<div class="flex flex-col items-center justify-center py-8 text-center bg-gray-50 dark:bg-white/5 rounded-xl border border-dashed border-gray-200 dark:border-white/10">
|
||||
<x-heroicon-o-pencil-square class="w-12 h-12 text-gray-300 dark:text-gray-600" />
|
||||
<p class="mt-2 text-sm font-medium text-gray-500 dark:text-gray-400">Belum ada tugas untuk sesi ini.</p>
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
@ -41,14 +41,22 @@
|
||||
<x-heroicon-s-clock class="w-3.5 h-3.5" />
|
||||
{{ $session->time_range }}
|
||||
</div>
|
||||
<div class="flex items-center gap-2 mt-2">
|
||||
<div class="flex items-center gap-1 text-[10px] font-bold text-amber-600 dark:text-amber-400">
|
||||
<x-heroicon-o-document-text class="w-3 h-3" />
|
||||
{{ $session->materials_count }} Materi
|
||||
<div class="flex gap-4">
|
||||
<div class="flex items-center gap-1.5 px-2 py-0.5 rounded-lg hover:bg-amber-50 dark:hover:bg-amber-900/10 cursor-pointer transition-colors"
|
||||
wire:click="mountAction('viewMaterials', { session: {{ $session->id }} })"
|
||||
onclick="event.stopPropagation()">
|
||||
<x-heroicon-o-document-text class="w-4 h-4 text-amber-500" />
|
||||
<span class="text-xs font-bold text-gray-600 dark:text-gray-400">
|
||||
{{ $session->materials_count }}<span class="ml-1 font-medium text-gray-400">Materi</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 text-[10px] font-bold text-info-600 dark:text-info-400">
|
||||
<x-heroicon-o-clipboard-document-list class="w-3 h-3" />
|
||||
{{ $session->assignments_count }} Tugas
|
||||
<div class="flex items-center gap-1.5 px-2 py-0.5 rounded-lg hover:bg-primary-50 dark:hover:bg-primary-900/10 cursor-pointer transition-colors"
|
||||
wire:click="mountAction('viewAssignments', { session: {{ $session->id }} })"
|
||||
onclick="event.stopPropagation()">
|
||||
<x-heroicon-o-pencil-square class="w-4 h-4 text-primary-500" />
|
||||
<span class="text-xs font-bold text-gray-600 dark:text-gray-400">
|
||||
{{ $session->assignments_count }}<span class="ml-1 font-medium text-gray-400">Tugas</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@if ($session->is_pending)
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
<div class="space-y-4 py-2">
|
||||
@forelse($materials as $material)
|
||||
<div class="flex items-center justify-between p-3 rounded-lg border border-gray-100 dark:border-white/5 bg-gray-50/50 dark:bg-white/5 hover:bg-white dark:hover:bg-white/10 transition-colors shadow-sm">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="p-2 rounded-lg bg-amber-100 dark:bg-amber-900/20 text-amber-600 dark:text-amber-400">
|
||||
<x-heroicon-o-document-text class="w-5 h-5" />
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="font-bold text-gray-900 dark:text-white leading-tight">{{ $material->title }}</span>
|
||||
<span class="text-[10px] text-gray-500 dark:text-gray-400 font-medium uppercase mt-0.5">
|
||||
Dibuat: {{ $material->created_at?->translatedFormat('d F Y') ?? '-' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<a href="{{ \App\Filament\Resources\Learning\Materials\MaterialResource::getUrl('index') . '?tableFilters[course_id][value]=' . $material->course_id . '&tableSearch=' . urlencode($material->title) }}"
|
||||
class="p-1.5 rounded-full hover:bg-gray-200 dark:hover:bg-white/10 text-gray-500 transition-colors"
|
||||
title="Lihat Detail">
|
||||
<x-heroicon-o-chevron-right class="w-5 h-5" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<div class="flex flex-col items-center justify-center py-8 text-center bg-gray-50 dark:bg-white/5 rounded-xl border border-dashed border-gray-200 dark:border-white/10">
|
||||
<x-heroicon-o-document-minus class="w-12 h-12 text-gray-300 dark:text-gray-600" />
|
||||
<p class="mt-2 text-sm font-medium text-gray-500 dark:text-gray-400">Belum ada materi untuk sesi ini.</p>
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
@ -36,12 +36,14 @@ class="flex items-center gap-1.5 font-bold text-success-600 dark:text-success-40
|
||||
<span class="text-[10px] font-bold text-gray-500">{{ $session->attendance_percentage }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5 font-bold text-amber-600 dark:text-amber-400">
|
||||
<div class="flex items-center gap-1.5 font-bold text-amber-600 dark:text-amber-400 hover:bg-amber-50 dark:hover:bg-amber-900/10 px-2 py-0.5 rounded-lg transition-colors cursor-pointer"
|
||||
wire:click="mountAction('viewMaterials', { session: {{ $session->id }} })">
|
||||
<x-heroicon-o-document-text class="w-4 h-4" />
|
||||
{{ $session->materials_count }} Materi
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5 font-bold text-info-600 dark:text-info-400">
|
||||
<x-heroicon-o-clipboard-document-list class="w-4 h-4" />
|
||||
<div class="flex items-center gap-1.5 font-bold text-primary-600 dark:text-primary-400 hover:bg-primary-50 dark:hover:bg-primary-900/10 px-2 py-0.5 rounded-lg transition-colors cursor-pointer"
|
||||
wire:click="mountAction('viewAssignments', { session: {{ $session->id }} })">
|
||||
<x-heroicon-o-pencil-square class="w-4 h-4" />
|
||||
{{ $session->assignments_count }} Tugas
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user