diff --git a/app/Filament/Pages/ReportPreview.php b/app/Filament/Pages/ReportPreview.php new file mode 100644 index 0000000..a713bc7 --- /dev/null +++ b/app/Filament/Pages/ReportPreview.php @@ -0,0 +1,138 @@ +loadData(); + $this->loadAssessment(); + } + + protected function loadData() : void + { + $this->student = Student::find(request()->query('studentId')); + $this->class = ClassRoom::find(request()->query('classId')); + $this->academic_year = AcademicYear::find(request()->query('yearId')); + $this->semester = request()->query('semester'); + $this->school_information = SchoolInformation::first(); + + $this->class_name = $this->toRoman($this->class->class_level) . ' ' . $this->extractClassLetter($this->class->class_name); + } + + protected function loadAssessment(): void + { + $requiredParams = ['studentId', 'classId', 'semester', 'yearId']; + + foreach ($requiredParams as $param) { + if (blank(request()->query($param))) { + Notification::make() + ->title('Missing Data') + ->body("The parameter '{$param}' is required.") + ->danger() + ->send(); + + return; + } + } + + $student_id = request()->query('studentId'); + $class_id = request()->query('classId'); + $semester = request()->query('semester'); + $year_id = request()->query('yearId'); + + // Class Student Mapping + $classSubjects = ClassSubject::with(['subject', 'class', 'academicYear']) + ->where('class_room_id', $class_id) + ->where('academic_year_id', $year_id) + ->get() + ->sortByDesc(function ($item) { + return $item->subject->name; + }) + ->toArray(); + + + $subjects = []; + + foreach ($classSubjects as $classSubject) { + $category = strtolower($classSubject['subject']['category']); + $subjectName = $classSubject['subject']['name']; + $subjectId = $classSubject['subject']['id']; + $subjects[$category][$subjectId] = $subjectName; + } + + $this->table["subjects"] = $subjects; + +// dd($subjects); + } + + public function extractClassLetter($className) + { + preg_match('/[A-Z]+$/i', trim($className), $matches); + return $matches[0] ?? ''; + } + + public function toRoman($number) + { + $map = [ + 'M' => 1000, + 'CM' => 900, + 'D' => 500, + 'CD' => 400, + 'C' => 100, + 'XC' => 90, + 'L' => 50, + 'XL' => 40, + 'X' => 10, + 'IX' => 9, + 'V' => 5, + 'IV' => 4, + 'I' => 1, + ]; + + $returnValue = ''; + while ($number > 0) { + foreach ($map as $roman => $int) { + if ($number >= $int) { + $number -= $int; + $returnValue .= $roman; + break; + } + } + } + + return $returnValue; + } + + public static function shouldRegisterNavigation(): bool + { + return false; + } +} diff --git a/app/Filament/Pages/SchoolInformation.php b/app/Filament/Pages/SchoolInformation.php new file mode 100644 index 0000000..255081b --- /dev/null +++ b/app/Filament/Pages/SchoolInformation.php @@ -0,0 +1,95 @@ +record = SchoolInformationModel::firstOrNew(); + $this->form->fill($this->record->toArray()); + } + + public function form(Form $form): Form + { + return $form + ->schema([ + Grid::make(2)->schema([ + TextInput::make('school_name')->label('Nama Sekolah')->required(), + TextInput::make('npsn') + ->label('NPSN') + ->numeric() + ->nullable(), + TextInput::make('nss') + ->label('NSS') + ->nullable(), + Textarea::make('address') + ->label('Alamat Sekolah') + ->nullable(), + TextInput::make('postal_code') + ->label('Kode Pos') + ->numeric() + ->nullable() + ->default(null), + TextInput::make('sub_district') + ->label('Desa / Kelurahan') + ->nullable(), + TextInput::make('district') + ->label('Kecamatan') + ->nullable(), + TextInput::make('city') + ->label('Kota / Kabupaten') + ->nullable(), + TextInput::make('province') + ->label('Provinsi') + ->nullable(), + TextInput::make('email') + ->label('Email') + ->nullable(), + TextInput::make('headmaster_name') + ->label('Nama Kepala Sekolah') + ->nullable(), + TextInput::make('headmaster_nip') + ->label('NIP Kepala Sekolah') + ->nullable(), + TextInput::make('phase') + ->label('Fase') + ->nullable(), + ]) + ]) + ->model($this->record) + ->statePath('data'); + } + + public function save(): void + { + $this->record->fill($this->data)->save(); + Notification::make() + ->title('Success') + ->body('Data saved successfully.') + ->success() + ->send(); + } +} diff --git a/app/Filament/Pages/StudentReport.php b/app/Filament/Pages/StudentReport.php index 7fd64c6..89fd180 100644 --- a/app/Filament/Pages/StudentReport.php +++ b/app/Filament/Pages/StudentReport.php @@ -118,6 +118,7 @@ class StudentReport extends Page }) ->toArray(); + $header = []; foreach ($classSubjects as $classSubject) { @@ -163,6 +164,7 @@ class StudentReport extends Page $studentData = [ 'name' => $fnl['name'], + 'id' => $fnl['student_id'], ]; $mapel = $fnl['umum'] ?? null; @@ -187,6 +189,7 @@ class StudentReport extends Page } $studentData['muatan lokal'] = $fnl['muatan lokal'] ?? null; + $studentData['seni'] = $fnl['seni'] ?? null; $result[] = $studentData; } diff --git a/app/Filament/Resources/AcademicYearResource.php b/app/Filament/Resources/AcademicYearResource.php index 3971a1d..76cd9fe 100644 --- a/app/Filament/Resources/AcademicYearResource.php +++ b/app/Filament/Resources/AcademicYearResource.php @@ -19,6 +19,8 @@ class AcademicYearResource extends Resource protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack'; + protected static ?string $navigationGroup = 'Academic Setup'; + public static function form(Form $form): Form { return $form diff --git a/app/Filament/Resources/ClassStudentResource.php b/app/Filament/Resources/ClassStudentResource.php index 127fde1..8c38c3e 100644 --- a/app/Filament/Resources/ClassStudentResource.php +++ b/app/Filament/Resources/ClassStudentResource.php @@ -22,6 +22,8 @@ class ClassStudentResource extends Resource protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack'; + protected static ?string $navigationGroup = 'Academic Setup'; + public static function form(Form $form): Form { return $form diff --git a/app/Filament/Resources/ClassSubjectResource.php b/app/Filament/Resources/ClassSubjectResource.php index d0eb708..7e395ee 100644 --- a/app/Filament/Resources/ClassSubjectResource.php +++ b/app/Filament/Resources/ClassSubjectResource.php @@ -21,7 +21,7 @@ class ClassSubjectResource extends Resource protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack'; - + protected static ?string $navigationGroup = 'Academic Setup'; public static function form(Form $form): Form { diff --git a/app/Filament/Resources/ExtracurricularAssessmentResource.php b/app/Filament/Resources/ExtracurricularAssessmentResource.php new file mode 100644 index 0000000..7e3383d --- /dev/null +++ b/app/Filament/Resources/ExtracurricularAssessmentResource.php @@ -0,0 +1,110 @@ +schema([ + Forms\Components\Select::make('class_student_id') + ->relationship('classStudent', 'id') // atau gunakan relasi yang lebih deskriptif jika ada + ->getOptionLabelFromRecordUsing(fn (ClassStudent $record) => + $record->class->class_name . ' - ' . $record->student->full_name . ' - ' . $record->academicYear->name) + ->searchable() + ->preload() + ->required(), + + Forms\Components\Select::make('extracurricular_id') + ->relationship('extracurricular', 'name') + ->label('Extracurricular') + ->options(Extracurricular::all()->pluck('name', 'id')) + ->searchable() + ->required(), + + Forms\Components\Select::make('semester') + ->options([ + 'first' => 'Ganjil', + 'second' => 'Genap', + ]) + ->required(), + + Forms\Components\TextInput::make('score') + ->numeric() + ->required(), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('classStudent.student.full_name') + ->label('Student') + ->searchable(), + + Tables\Columns\TextColumn::make('classStudent.class.class_name') + ->label('Class') + ->searchable(), + + Tables\Columns\TextColumn::make('classStudent.academicYear.name') + ->label('Academic Year'), + + Tables\Columns\TextColumn::make('extracurricular.name') + ->label('Extracurricular'), + + Tables\Columns\TextColumn::make('semester'), + + Tables\Columns\TextColumn::make('score') + ->sortable(), + ]) + ->filters([ + // + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + // + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListExtracurricularAssessments::route('/'), + 'create' => Pages\CreateExtracurricularAssessment::route('/create'), + 'edit' => Pages\EditExtracurricularAssessment::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/ExtracurricularAssessmentResource/Pages/CreateExtracurricularAssessment.php b/app/Filament/Resources/ExtracurricularAssessmentResource/Pages/CreateExtracurricularAssessment.php new file mode 100644 index 0000000..cfc9636 --- /dev/null +++ b/app/Filament/Resources/ExtracurricularAssessmentResource/Pages/CreateExtracurricularAssessment.php @@ -0,0 +1,12 @@ +belongsTo(AcademicYear::class, 'academic_year_id'); } + + public function extracurricularAssessments() : HasMany + { + return $this->hasMany(ExtracurricularAssessment::class); + } } diff --git a/app/Models/Extracurricular.php b/app/Models/Extracurricular.php index f658ed3..3a5f00d 100644 --- a/app/Models/Extracurricular.php +++ b/app/Models/Extracurricular.php @@ -7,4 +7,9 @@ use Illuminate\Database\Eloquent\Model; class Extracurricular extends Model { protected $fillable = ['name', 'description']; + + public function assessments() + { + return $this->hasMany(ExtracurricularAssessment::class); + } } diff --git a/app/Models/ExtracurricularAssessment.php b/app/Models/ExtracurricularAssessment.php new file mode 100644 index 0000000..347b9b1 --- /dev/null +++ b/app/Models/ExtracurricularAssessment.php @@ -0,0 +1,25 @@ +belongsTo(ClassStudent::class, 'class_student_id'); + } + + public function extracurricular() + { + return $this->belongsTo(Extracurricular::class, 'extracurricular_id'); + } +} diff --git a/app/Models/SchoolInformation.php b/app/Models/SchoolInformation.php new file mode 100644 index 0000000..7b5ac99 --- /dev/null +++ b/app/Models/SchoolInformation.php @@ -0,0 +1,24 @@ +id(); + $table->foreignId('class_student_id')->constrained('class_students'); + $table->foreignId('extracurricular_id')->constrained('extracurriculars'); + $table->float('score'); + $table->string('semester'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('extracurricular_assessments'); + } +}; diff --git a/database/migrations/2025_05_16_053344_create_school_information_table.php b/database/migrations/2025_05_16_053344_create_school_information_table.php new file mode 100644 index 0000000..98901ca --- /dev/null +++ b/database/migrations/2025_05_16_053344_create_school_information_table.php @@ -0,0 +1,40 @@ +id(); + $table->string('school_name'); + $table->string('npsn')->nullable(); + $table->string('nss')->nullable(); + $table->string('address')->nullable(); + $table->string('postal_code')->nullable(); + $table->string('sub_district')->nullable(); + $table->string('district')->nullable(); + $table->string('city')->nullable(); + $table->string('province')->nullable(); + $table->string('email')->nullable(); + $table->string('headmaster_name')->nullable(); + $table->string('headmaster_nip')->nullable(); + $table->string('phase')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('school_information'); + } +}; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index a466e15..2c46452 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -21,6 +21,7 @@ class DatabaseSeeder extends Seeder ClassSubjectSeeder::class, ClassStudentSeeder::class, HomeRoomTeacherSeeder::class, + SchoolInformationSeeder::class, ]); } } diff --git a/database/seeders/SchoolInformationSeeder.php b/database/seeders/SchoolInformationSeeder.php new file mode 100644 index 0000000..de1e409 --- /dev/null +++ b/database/seeders/SchoolInformationSeeder.php @@ -0,0 +1,35 @@ + 1], + [ + 'school_name' => 'UPTD SDN Cinere 1', + 'npsn' => null, + 'nss' => null, + 'address' => 'Jl. Cinere Raya No.18, Depok', + 'postal_code' => 0, + 'sub_district' => 'Cinere', + 'district' => 'Cinere', + 'city' => 'Depok', + 'province' => 'Jawa Barat', + 'email' => null, + 'headmaster_name' => 'Drs. Nasim', + 'headmaster_nip' => '196804191992031008', + 'phase' => 'C', + ] + ); + } +} diff --git a/resources/views/filament/pages/report-preview.blade.php b/resources/views/filament/pages/report-preview.blade.php new file mode 100644 index 0000000..d4a31f0 --- /dev/null +++ b/resources/views/filament/pages/report-preview.blade.php @@ -0,0 +1,194 @@ + +
+ {{-- Report Preview --}} +
+
+

Laporan Hasil Belajar

+

(RAPOR)

+
+ +
+ + + + + + + + + + + + + + + + + +
Nama Peserta Didik: {{ $this->student->full_name ?? "-" }}Kelas: {{ $this->class_name ?? "-" }}
NISN/NIS: {{ $this->student->nisn ?? '-' }} / {{ $this->student->nis ?? '-' }}Fase: -
Sekolah: {{ $this->school_information->school_name ?? "-" }}Semester: {{ $this->semester === 'first' ? 'I' : 'II' }}
Alamat:{{ $this->school_information->address ?? "-" }}Tahun Ajaran: {{ $this->academic_year->name ?? "-" }}
+
+ +
+ + + + + + + + + + + + @php + $i = 1; + @endphp + + @if(!empty($this->table['subjects']['umum'])) + @foreach($this->table['subjects']['umum'] as $subjectId => $subjectName) + + + + + + + @php + $i++; + @endphp + @endforeach + @endif + @if(!empty($this->table['subjects']['seni'])) + + + + + @foreach($this->table['subjects']['seni'] as $subjectId => $subjectName) + + + + + + + @php + $i++; + @endphp + @endforeach + @endif + +
NoMuatan PelajaranNilai AkhirCapaian Kompetensi
{{ $i }}{{ $subjectName }}90Ananda sangat memahami materi ajaran dan menunjukkan perilaku religius dalam keseharian.
{{ $i }}Seni
a{{ $subjectName }}90Ananda sangat memahami materi ajaran dan menunjukkan perilaku religius dalam keseharian.
+ +

Muatan Lokal

+ + + + + + + + + + + + + @if(!empty($this->table['subjects']['muatan lokal'])) + @foreach($this->table['subjects']['muatan lokal'] as $subjectId => $subjectName) + + + + + + + @php + $i++; + @endphp + @endforeach + @endif + +
NoMuatan PelajaranNilai AkhirCapaian Kompetensi
{{ $i }}{{ $subjectName }}90Ananda sangat memahami materi ajaran dan menunjukkan perilaku religius dalam keseharian.
+ + + + + + + + + + + + + + + + + + + +
NoEktrakurikulerPredikatKeterangan
1PramukaASangat Berkembang
+ + + + + + + + + + + + + + +
Ketidakhadiran
Sakit: 2 hari
Izin: 1 hari
Tanpa Keterangan: 0 hari
+ +
+
+ Orang Tua / Wali


+ ______________________ +
+ +
+ @php + \Carbon\Carbon::setLocale('id'); + @endphp + + Depok, {{ \Carbon\Carbon::now()->translatedFormat('d F Y') }}
+ Wali Kelas {{ $this->class_name ?? "-" }}


+ Siti Mawarni, S.Pd
+ NIP. 197502021990121001 +
+
+ +
+ Mengetahui,
+ Kepala Sekolah


+ {{ $this->school_information->headmaster_name ?? "-" }}
+ NIP. {{ $this->school_information->headmaster_nip ?? "-" }} +
+
+
+ {{-- Sidebar Config --}} +
+
+
+

Input Absensi

+ + + + + + + + +
+ +
+

Catatan Wali Kelas

+ +
+ + Simpan +
+
+
+
diff --git a/resources/views/filament/pages/school-information.blade.php b/resources/views/filament/pages/school-information.blade.php new file mode 100644 index 0000000..9a61e9d --- /dev/null +++ b/resources/views/filament/pages/school-information.blade.php @@ -0,0 +1,14 @@ + +
+ {{ $this->form }} + +
+ +
+
+
diff --git a/resources/views/filament/pages/student-report.blade.php b/resources/views/filament/pages/student-report.blade.php index a6abd90..dc8305e 100644 --- a/resources/views/filament/pages/student-report.blade.php +++ b/resources/views/filament/pages/student-report.blade.php @@ -1,4 +1,4 @@ - + {{ $this->form }} @if(!empty($this->list)) @@ -14,7 +14,7 @@ - @foreach(['umum', 'muatan lokal'] as $category) + @foreach(['umum','seni', 'muatan lokal'] as $category) @if(!empty($this->list['header'][$category])) @@ -23,11 +23,17 @@ @endif @endforeach + + + + Action + + - @foreach(['umum', 'muatan lokal'] as $category) + @foreach(['umum', 'seni', 'muatan lokal'] as $category) @if(!empty($this->list['header'][$category])) @foreach($this->list['header'][$category] as $subjectName) @@ -51,8 +57,7 @@ - - @foreach(['umum', 'muatan lokal'] as $category) + @foreach(['umum', 'seni','muatan lokal'] as $category) @if(!empty($this->list['header'][$category])) @foreach($this->list['header'][$category] as $subjectId => $subjectName) @@ -63,6 +68,20 @@ @endforeach @endif @endforeach + + + Raport + + @endforeach