add report student

This commit is contained in:
reihanrere 2025-05-15 10:02:57 +07:00
parent edf02bc09a
commit dee2805504
72 changed files with 1965 additions and 353 deletions

View File

@ -0,0 +1,223 @@
<?php
namespace App\Filament\Pages;
use App\Models\AcademicYear;
use App\Models\Assessment;
use App\Models\ClassRoom;
use App\Models\ClassStudent;
use App\Models\ClassSubject;
use App\Models\Student;
use App\Models\Subject;
use App\Models\TeacherSubject;
use Filament\Forms\Components\Select;
use Filament\Forms\Form;
use Filament\Pages\Page;
class StudentReport extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static string $view = 'filament.pages.student-report';
protected static ?string $navigationGroup = 'Academic Management';
public $class_id;
public $academic_year;
public $semester;
public ?array $data;
public $list;
public static function canAccess(): bool
{
return auth()->user()->hasAnyRole(['super_admin']);
}
public static function shouldRegisterNavigation(): bool
{
return auth()->user()->hasAnyRole(['super_admin']);
}
public function mount(): void
{
$this->class = null;
$this->academicYear = null;
$this->semester = null;
$this->data = [];
}
public function form(Form $form): Form
{
return $form->schema([
Select::make('class_id')
->label('Class')
->required()
->options(ClassRoom::pluck('class_name', 'id')->toArray())
->searchable()
->reactive()
->afterStateUpdated(function ($state) {
$this->class_id = $state;
$this->data['class_id'] = $state; // Update data array
$this->loadData();
}),
Select::make('academic_year')
->label('Academic Year')
->required()
->options(AcademicYear::pluck('name', 'id')->toArray())
->searchable()
->reactive()
->afterStateUpdated(function ($state) {
$this->academic_year = $state;
$this->data['academic_year'] = $state; // Update data array
$this->loadData();
}),
Select::make('semester')
->label('Semester')
->required()
->options([
'first' => 'First Semester',
'second' => 'Second Semester'
])
->reactive()
->afterStateUpdated(function ($state) {
$this->semester = $state;
$this->data['semester'] = $state;
$this->loadData();
}),
])->columns(3);
}
protected function loadData(): void
{
if (count($this->data) < 3) {
$this->list = [];
return;
}
$groupedAssessment = [];
$assessments = Assessment::where('semester', $this->semester)
->whereHas('teacherSubject', function($query) {
$query->where('academic_year_id', $this->academic_year)
->where('class_id', $this->class_id);
})
->with('teacherSubject', 'student')
->get()
->toArray();
$classSubjects = ClassSubject::with(['subject', 'class', 'academicYear'])
->where('class_room_id', $this->class_id)
->where('academic_year_id', $this->academic_year)
->get()
->sortByDesc(function ($item) {
return $item->subject->name;
})
->toArray();
$header = [];
foreach ($classSubjects as $classSubject) {
$category = strtolower($classSubject['subject']['category']);
$subjectName = $classSubject['subject']['name'];
$subjectId = $classSubject['subject']['id'];
$header[$category][$subjectId] = $subjectName;
}
$students = ClassStudent::with(['class', 'academicYear', 'student'])
->where('class_room_id', $this->class_id)
->where('academic_year_id', $this->academic_year)
->get()
->map(function($student) {
return $student['student'];
})
->toArray();
$finals = [];
foreach ($students as $student) {
$studentData = [
'student_id' => $student['id'],
'name' => $student['full_name'],
];
foreach ($header as $category => $subjects) {
foreach ($subjects as $subjectId => $subjectName) {
$matchingAssessment = collect($assessments)->first(function ($a) use ($student, $subjectId) {
return $a['student_id'] == $student['id'] && $a['teacher_subject']['subject_id'] == $subjectId;
});
$studentData[$category][$subjectId] = $matchingAssessment['score'] ?? '-'; // atau null
}
}
$finals[] = $studentData;
}
$result = [];
foreach ($finals as $final => $fnl) {
$existStudent = Student::where('id', $fnl['student_id'])->firstOrFail();
$studentData = [
'name' => $fnl['name'],
];
$mapel = $fnl['umum'] ?? null;
if ($mapel) {
foreach ($mapel as $key => $value) {
$existSubject = Subject::where('id', $key)->firstOrFail();
if ($existSubject->is_religious) {
$studentReligion = strtolower($existStudent->religion); // contoh: "islam"
$subjectName = strtolower($existSubject->name); // contoh: "pendidikan agama islam"
if (str_contains($subjectName, $studentReligion)) {
// Hanya mapel agama yang sesuai dengan agama siswa dimasukkan ke umum[0]
$studentData['umum'][0] = $value;
}
// Mapel agama lain tidak dimasukkan sama sekali
} else {
$studentData['umum'][$key] = $value;
}
}
}
$studentData['muatan lokal'] = $fnl['muatan lokal'] ?? null;
$result[] = $studentData;
}
$groupedAssessment["data"] = $result;
$groupedSubjectsHeader = [];
$groupedSubjectsHeader['name'] = "Nama";
$religionAdded = false;
foreach ($classSubjects as $classSubject) {
$category = strtolower($classSubject['subject']['category']);
$subjectName = $classSubject['subject']['name'];
$isReligion = $classSubject['subject']['is_religious'];
$subjectId = $classSubject['subject']['id'];
if ($isReligion) {
if (!$religionAdded) {
$groupedSubjectsHeader['umum'][0] = 'Pendidikan Agama';
$religionAdded = true;
}
continue;
}
$groupedSubjectsHeader[$category][$subjectId] = $subjectName;
}
$groupedAssessment["header"] = $groupedSubjectsHeader;
$this->list = $groupedAssessment;
}
}

View File

@ -0,0 +1,105 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\AcademicYearResource\Pages;
use App\Filament\Resources\AcademicYearResource\RelationManagers;
use App\Models\AcademicYear;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class AcademicYearResource extends Resource
{
protected static ?string $model = AcademicYear::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name')
->required()
->placeholder("ex: 2024/2025")
->maxLength(255),
Forms\Components\Toggle::make('is_active')
->required(),
Forms\Components\DatePicker::make('start_date'),
Forms\Components\DatePicker::make('end_date'),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('name')
->searchable(),
Tables\Columns\IconColumn::make('is_active')
->boolean(),
Tables\Columns\TextColumn::make('start_date')
->date()
->sortable(),
Tables\Columns\TextColumn::make('end_date')
->date()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->emptyStateActions([
Tables\Actions\CreateAction::make(),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListAcademicYears::route('/'),
'create' => Pages\CreateAcademicYear::route('/create'),
'edit' => Pages\EditAcademicYear::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace App\Filament\Resources\AcademicYearResource\Pages;
use App\Filament\Resources\AcademicYearResource;
use App\Models\AcademicYear;
use App\Models\ClassStudent;
use Filament\Actions;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\CreateRecord;
class CreateAcademicYear extends CreateRecord
{
protected static string $resource = AcademicYearResource::class;
protected function mutateFormDataBeforeCreate(array $data): array
{
$exists = AcademicYear::where('name', $data['name'])
->exists();
if ($exists) {
Notification::make()
->title('Failed to save')
->body('A record already exists.')
->danger()
->send();
$this->halt(); // Stop the save process
}
return $data;
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace App\Filament\Resources\AcademicYearResource\Pages;
use App\Filament\Resources\AcademicYearResource;
use App\Models\AcademicYear;
use App\Models\ClassStudent;
use Filament\Actions;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\EditRecord;
class EditAcademicYear extends EditRecord
{
protected static string $resource = AcademicYearResource::class;
protected function mutateFormDataBeforeSave(array $data): array
{
$exists = AcademicYear::where('name', $data['name'])
->exists();
if ($exists) {
Notification::make()
->title('Failed to save')
->body('A record already exists.')
->danger()
->send();
$this->halt(); // Stop the save process
}
return $data;
}
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\AcademicYearResource\Pages;
use App\Filament\Resources\AcademicYearResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListAcademicYears extends ListRecords
{
protected static string $resource = AcademicYearResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@ -6,6 +6,7 @@ use App\Filament\Resources\AssessmentResource\Pages;
use App\Filament\Resources\AssessmentResource\RelationManagers;
use App\Models\Assessment;
use App\Models\AssessmentComponent;
use App\Models\ClassStudent;
use App\Models\Student;
use App\Models\TeacherSubject;
use Filament\Forms;
@ -33,15 +34,14 @@ class AssessmentResource extends Resource
->required()
->relationship('teacherSubject', 'id')
->getOptionLabelFromRecordUsing(fn (TeacherSubject $record) =>
$record->teacher->name . ' - ' . $record->subject->name . ' - ' . $record->class->class_name . ' - ' . $record->academic_year)
$record->teacher->name . ' - ' . $record->subject->name . ' - ' . $record->class->class_name . ' - ' . $record->academicYear->name)
->searchable()
->preload()
->afterStateUpdated(function (callable $set, $state) {
// Filter siswa berdasarkan kelas yang dipilih dalam teacher_subject_id
if ($state) {
$teacherSubject = TeacherSubject::find($state);
if ($teacherSubject) {
$set('student_id', null); // Reset student_id jika teacher_subject_id berubah
$set('student_id', null);
}
}
})
@ -51,14 +51,15 @@ class AssessmentResource extends Resource
->label('Student')
->required()
->searchable()
// Filter opsi siswa berdasarkan kelas yang terkait dengan teacher_subject_id
->options(function ($get) {
$teacherSubjectId = $get('teacher_subject_id');
if ($teacherSubjectId) {
$teacherSubject = TeacherSubject::find($teacherSubjectId);
// Ambil siswa yang memiliki kelas yang sesuai dengan teacher_subject_id
$students = Student::where('class_id', $teacherSubject->class_id)
->pluck('full_name', 'id')
$students = ClassStudent::where('class_room_id', $teacherSubject->class_id)
->where('academic_year_id', $teacherSubject->academic_year_id)
->with('student')
->get()
->pluck('student.full_name', 'id')
->toArray();
return $students;
@ -68,8 +69,15 @@ class AssessmentResource extends Resource
->getOptionLabelUsing(function ($value) {
$student = Student::find($value);
return $student ? $student->full_name . ' (' . $student->nis . ')' : null;
})
->required(),
}),
Forms\Components\Select::make('semester')
->label('Semester')
->required()
->options([
'first' => 'First Semester',
'second' => 'Second Semester'
]),
Forms\Components\TextInput::make('score')
->label('Score')
@ -122,6 +130,9 @@ class AssessmentResource extends Resource
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
])
->emptyStateActions([
Tables\Actions\CreateAction::make(),
]);
}

View File

@ -15,7 +15,7 @@ class ListAssessments extends ListRecords
return [
Actions\CreateAction::make(),
Actions\Action::make('multiple')
->label('Multiple Attendance')
->label('Multiple Assessments')
->url('assessments/multiple')
->icon('heroicon-o-user-group'),
];

View File

@ -5,13 +5,16 @@ namespace App\Filament\Resources\AssessmentResource\Pages;
use App\Filament\Resources\AssessmentResource;
use App\Models\Assessment;
use App\Models\Attendances;
use App\Models\ClassStudent;
use Filament\Actions;
use Filament\Forms\Components\Select;
use Filament\Resources\Pages\page;
use App\Models\Student;
use App\Models\TeacherSubject;
use Filament\Forms;
use Filament\Notifications\Notification;
use Illuminate\Support\Collection;
use function Symfony\Component\Translation\t;
class MultipleAssessments extends page
{
@ -21,10 +24,15 @@ class MultipleAssessments extends page
use Forms\Concerns\InteractsWithForms;
public ?array $data = [];
public ?int $teacherSubjectId = null;
public $teacherSubject;
public array $students = [];
public $semester = 'first';
public function mount(): void
{
$this->form->fill();
@ -33,18 +41,38 @@ class MultipleAssessments extends page
protected function getFormSchema(): array
{
return [
Forms\Components\Grid::make(2)
->schema([
Forms\Components\Select::make('teacherSubjectId')
->label('Teacher Subject')
->options(
TeacherSubject::with(['teacher', 'subject', 'class'])->get()->mapWithKeys(function ($item) {
TeacherSubject::with(['teacher', 'subject', 'class', 'academicYear'])->get()->mapWithKeys(function ($item) {
return [
$item->id => "{$item->teacher->name} - {$item->subject->name} - {$item->class->class_name}"
$item->id => "{$item->teacher->name} - {$item->subject->name} - {$item->class->class_name} - {$item->academicYear->name}"
];
})->toArray()
)
->searchable()
->reactive()
->afterStateUpdated(fn ($state) => $this->loadStudents()),
->afterStateUpdated(function ($state) {
$this->teacherSubjectId = $state;
$this->loadStudents();
}),
Forms\Components\Select::make('semester')
->label('Semester')
->required()
->default('first')
->options([
'first' => 'First Semester',
'second' => 'Second Semester'
])
->live()
->afterStateUpdated(function ($state) {
$this->semester = $state;
$this->loadStudents();
}),
]),
];
}
@ -55,34 +83,47 @@ class MultipleAssessments extends page
return;
}
$teacherSubject = TeacherSubject::find($this->teacherSubjectId);
$this->teacherSubject = TeacherSubject::with(['subject','class','academicYear','teacher'])
->where('id', $this->teacherSubjectId)
->firstOrFail();
if (!$teacherSubject) {
$this->students = [];
$classStudents = ClassStudent::where('class_room_id', $this->teacherSubject->class_id)
->where('academic_year_id', $this->teacherSubject->academic_year_id)
->with('student')
->get();
Notification::make()
->title('Not Found')
->body('Selected teacher subject not found.')
->danger()
->send();
$isSubjectReligion = $this->teacherSubject->subject->is_religious;
$subjectName = strtolower($this->teacherSubject->subject->name);
return;
}
$result = [];
foreach ($classStudents as $classStudent) {
$student = $classStudent->student;
if (!$student) continue; // Jaga-jaga kalau relasi student-nya null
$this->students = Student::where('class_id', $teacherSubject->class_id)
->get()
->map(function ($student) {
$existingAssessment = Assessment::where('student_id', $student->id)
->where('teacher_subject_id', $this->teacherSubjectId)
->where('semester', $this->semester)
->first();
return [
if ($isSubjectReligion) {
$studentReligion = strtolower($student->religion);
if (!str_contains($subjectName, $studentReligion)) {
continue; // Skip kalau agama tidak cocok
}
}
$result[] = [
'id' => $student->id,
'name' => $student->full_name,
'nis' => $student->nis,
'score' => $existingAssessment ? $existingAssessment->score : null,
];
})->toArray();
}
$this->students = $result;
}
public function submit(): void
@ -106,6 +147,7 @@ class MultipleAssessments extends page
],
[
'score' => $student['score'],
'semester' => $this->semester,
]
);
}

View File

@ -5,6 +5,7 @@ namespace App\Filament\Resources;
use App\Filament\Resources\AttendancesResource\Pages;
use App\Models\Attendances;
use App\Models\ClassRoom;
use App\Models\ClassStudent;
use App\Models\Student;
use App\Models\Subject;
use App\Models\TeacherSubject;
@ -26,22 +27,21 @@ class AttendancesResource extends Resource
{
return $form
->schema([
Forms\Components\Section::make('Informasi Absensi')
Forms\Components\Section::make('Data Absensi')
->schema([
Forms\Components\Select::make('teacher_subject_id')
->label('Teacher Subject')
->required()
->relationship('teacherSubject', 'id')
->getOptionLabelFromRecordUsing(fn (TeacherSubject $record) =>
$record->teacher->name . ' - ' . $record->subject->name . ' - ' . $record->class->class_name . ' - ' . $record->academic_year)
$record->teacher->name . ' - ' . $record->subject->name . ' - ' . $record->class->class_name . ' - ' . $record->academicYear->name)
->searchable()
->preload()
->afterStateUpdated(function (callable $set, $state) {
// Filter siswa berdasarkan kelas yang dipilih dalam teacher_subject_id
if ($state) {
$teacherSubject = TeacherSubject::find($state);
if ($teacherSubject) {
$set('student_id', null); // Reset student_id jika teacher_subject_id berubah
$set('student_id', null);
}
}
})
@ -51,20 +51,21 @@ class AttendancesResource extends Resource
->label('Date')
->required()
->default(now())
->maxDate(now()),
->live(),
Forms\Components\Select::make('student_id')
->label('Student')
->required()
->searchable()
// Filter opsi siswa berdasarkan kelas yang terkait dengan teacher_subject_id
->options(function ($get) {
$teacherSubjectId = $get('teacher_subject_id');
if ($teacherSubjectId) {
$teacherSubject = TeacherSubject::find($teacherSubjectId);
// Ambil siswa yang memiliki kelas yang sesuai dengan teacher_subject_id
$students = Student::where('class_id', $teacherSubject->class_id)
->pluck('full_name', 'id')
$students = ClassStudent::where('class_room_id', $teacherSubject->class_id)
->where('academic_year_id', $teacherSubject->academic_year_id)
->with('student')
->get()
->pluck('student.full_name', 'id')
->toArray();
return $students;
@ -153,7 +154,7 @@ class AttendancesResource extends Resource
'second' => 'Second Semester'
}),
Tables\Columns\TextColumn::make('teacherSubject.academic_year')
Tables\Columns\TextColumn::make('teacherSubject.academicYear.name')
->label('Academic Year')
->searchable(),

View File

@ -3,13 +3,36 @@
namespace App\Filament\Resources\AttendancesResource\Pages;
use App\Filament\Resources\AttendancesResource;
use App\Models\Assessment;
use App\Models\Attendances;
use Filament\Actions;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\EditRecord;
class EditAttendances extends EditRecord
{
protected static string $resource = AttendancesResource::class;
protected function mutateFormDataBeforeSave(array $data): array
{
$exists = Attendances::where('teacher_subject_id', $data['teacher_subject_id'])
->where('student_id', $data['student_id'])
->where('id', '!=', $this->record->id) // ignore current record
->exists();
if ($exists) {
Notification::make()
->title('Failed to save')
->body('An assessment for this teacher, subject, and student combination already exists.')
->danger()
->send();
$this->halt();
}
return $data;
}
protected function getHeaderActions(): array
{
return [

View File

@ -3,8 +3,10 @@
namespace App\Filament\Resources\AttendancesResource\Pages;
use App\Filament\Resources\AttendancesResource;
use App\Models\Assessment;
use App\Models\Attendances;
use App\Models\ClassRoom;
use App\Models\ClassStudent;
use App\Models\Student;
use App\Models\TeacherSubject;
use Filament\Actions;
@ -26,7 +28,8 @@ class MultipleAttendances extends Page
public $teacherSubject;
public $attendanceDate;
public $semester = 'first'; // Default semester
public $semester = 'first';
public $students = [];
public function mount(): void
@ -48,7 +51,7 @@ class MultipleAttendances extends Page
->options(TeacherSubject::with(['teacher', 'subject', 'class'])
->get()
->mapWithKeys(fn ($item) => [
$item->id => $item->teacher->name . ' - ' . $item->subject->name . ' - ' . $item->class->class_name
$item->id => $item->teacher->name . ' - ' . $item->subject->name . ' - ' . $item->class->class_name . ' - ' . $item->academicYear->name
]))
->searchable()
->live()
@ -61,7 +64,6 @@ class MultipleAttendances extends Page
->label('Attendance Date')
->required()
->default(now())
->maxDate(now())
->live()
->afterStateUpdated(function ($state) {
$this->attendanceDate = $state;
@ -81,7 +83,8 @@ class MultipleAttendances extends Page
$this->loadStudents();
}),
])
->statePath('data');
->statePath('data')
->columns(3);
}
protected function loadStudents(): void
@ -93,25 +96,67 @@ class MultipleAttendances extends Page
$this->teacherSubject = TeacherSubject::where('id', $this->teacherSubjectId)->firstOrFail();
$this->students = Student::where('class_id', $this->teacherSubject->class_id)
->orderBy('full_name')
->get()
->map(function ($student) {
$classStudents = ClassStudent::where('class_room_id', $this->teacherSubject->class_id)
->where('academic_year_id', $this->teacherSubject->academic_year_id)
->with('student')
->get();
$isSubjectReligion = $this->teacherSubject->subject->is_religious;
$subjectName = strtolower($this->teacherSubject->subject->name);
$result = [];
foreach ($classStudents as $classStudent) {
$student = $classStudent->student;
if (!$student) continue;
if ($isSubjectReligion) {
$studentReligion = strtolower($student->religion ?? '');
if (!str_contains($subjectName, $studentReligion)) {
continue;
}
}
$existingAttendance = Attendances::where('student_id', $student->id)
->where('teacher_subject_id', $this->teacherSubjectId)
->whereDate('date', $this->attendanceDate)
->where('semester', $this->semester)
->first();
return [
$result[] = [
'id' => $student->id,
'name' => $student->full_name,
'nis' => $student->nis,
'status' => $existingAttendance ? $existingAttendance->status : null,
'attendance_id' => $existingAttendance ? $existingAttendance->id : null,
];
})
->toArray();
}
$this->students = $result;
// $this->students = ClassStudent::where('class_room_id', $this->teacherSubjectId)
// ->where('academic_year_id', $this->teacherSubject->academic_year_id)
// ->with('student')
// ->get()
// ->map(function ($student) {
// $existingAttendance = Attendances::where('student_id', $student->student_id)
// ->where('teacher_subject_id', $this->teacherSubjectId)
// ->whereDate('date', $this->attendanceDate)
// ->where('semester', $this->semester)
// ->first();
//
// return [
// 'id' => $student->student->id,
// 'name' => $student->student->full_name,
// 'nis' => $student->student->nis,
// 'status' => $existingAttendance ? $existingAttendance->status : null,
// 'attendance_id' => $existingAttendance ? $existingAttendance->id : null,
// ];
// })
// ->values()
// ->toArray();
}
public function markAll($status): void

View File

@ -43,24 +43,6 @@ class ClassRoomResource extends Resource
'5' => 'Class 5',
'6' => 'Class 6',
]),
Forms\Components\Select::make('homeroom_teacher_id')
->label('Homeroom Teacher')
->relationship(
name: 'homeroomTeacher',
titleAttribute: 'name',
modifyQueryUsing: fn ($query) => $query->whereHas('roles', function ($q) {
$q->where('name', 'teacher');
}),
)
->searchable()
->preload()
->required(),
Forms\Components\TextInput::make('academic_year')
->label('Academic Year')
->required()
->placeholder('Example: 2023/2024')
->maxLength(9),
])->columns(2)
]);
}
@ -73,10 +55,6 @@ class ClassRoomResource extends Resource
->searchable(),
Tables\Columns\TextColumn::make('class_level')
->searchable(),
Tables\Columns\TextColumn::make('homeroomTeacher.name')
->label('Homeroom Teacher'),
Tables\Columns\TextColumn::make('academic_year')
->searchable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
@ -87,16 +65,28 @@ class ClassRoomResource extends Resource
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
Tables\Actions\RestoreAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
])
->emptyStateActions([
Tables\Actions\CreateAction::make(),
]);
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}

View File

@ -0,0 +1,112 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\ClassStudentResource\Pages;
use App\Filament\Resources\ClassStudentResource\RelationManagers;
use App\Models\AcademicYear;
use App\Models\ClassRoom;
use App\Models\ClassStudent;
use App\Models\Student;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class ClassStudentResource extends Resource
{
protected static ?string $model = ClassStudent::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('class_room_id')
->label('Class Room')
->required()
->options(ClassRoom::pluck('class_name', 'id')->toArray())
->searchable()
->native(false),
Forms\Components\Select::make('student_id')
->label('Student')
->required()
->options(Student::pluck('full_name', 'id')->toArray())
->searchable()
->native(false),
Forms\Components\Select::make('academic_year_id')
->label('Academic Year')
->required()
->options(AcademicYear::pluck('name', 'id')->toArray())
->searchable()
->native(false),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('class.class_name')
->label('Class Room')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('student.full_name')
->label('Student')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('academicYear.name')
->label('Academic Year')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
])
->emptyStateActions([
Tables\Actions\CreateAction::make(),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListClassStudents::route('/'),
'create' => Pages\CreateClassStudent::route('/create'),
'edit' => Pages\EditClassStudent::route('/{record}/edit'),
];
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace App\Filament\Resources\ClassStudentResource\Pages;
use App\Filament\Resources\ClassStudentResource;
use App\Models\Assessment;
use App\Models\ClassStudent;
use Filament\Actions;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\CreateRecord;
class CreateClassStudent extends CreateRecord
{
protected static string $resource = ClassStudentResource::class;
protected function mutateFormDataBeforeCreate(array $data): array
{
$exists = ClassStudent::where('class_room_id', $data['class_room_id'])
->where('student_id', $data['student_id'])
->where('academic_year_id', $data['academic_year_id'])
->exists();
if ($exists) {
Notification::make()
->title('Failed to save')
->body('A record for this class room, student, and academic year combination already exists.')
->danger()
->send();
$this->halt(); // Stop the save process
}
return $data;
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace App\Filament\Resources\ClassStudentResource\Pages;
use App\Filament\Resources\ClassStudentResource;
use App\Models\ClassStudent;
use Filament\Actions;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\EditRecord;
class EditClassStudent extends EditRecord
{
protected static string $resource = ClassStudentResource::class;
protected function mutateFormDataBeforeSave(array $data): array
{
$exists = ClassStudent::where('class_room_id', $data['class_room_id'])
->where('student_id', $data['student_id'])
->where('academic_year_id', $data['academic_year_id'])
->exists();
if ($exists) {
Notification::make()
->title('Failed to save')
->body('A record for this class room, student, and academic year combination already exists.')
->danger()
->send();
$this->halt(); // Stop the save process
}
return $data;
}
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ClassStudentResource\Pages;
use App\Filament\Resources\ClassStudentResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListClassStudents extends ListRecords
{
protected static string $resource = ClassStudentResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@ -0,0 +1,83 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\ClassSubjectResource\Pages;
use App\Filament\Resources\ClassSubjectResource\RelationManagers;
use App\Models\ClassSubject;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\Select;
use Filament\Tables\Columns\TextColumn;
class ClassSubjectResource extends Resource
{
protected static ?string $model = ClassSubject::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
public static function form(Form $form): Form
{
return $form
->schema([
Select::make('class_room_id')
->label('Kelas')
->relationship('class', 'class_name')
->required(),
Select::make('subject_id')
->label('Mata Pelajaran')
->relationship('subject', 'name')
->required(),
Select::make('academic_year_id')
->label('Tahun Ajaran')
->relationship('academicYear', 'name') // ganti "name" jika kolomnya berbeda
->required(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('class.class_name')->label('Kelas')->sortable()->searchable(),
TextColumn::make('subject.name')->label('Mata Pelajaran')->sortable()->searchable(),
TextColumn::make('academicYear.name')->label('Tahun Ajaran')->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\ListClassSubjects::route('/'),
'create' => Pages\CreateClassSubject::route('/create'),
'edit' => Pages\EditClassSubject::route('/{record}/edit'),
];
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace App\Filament\Resources\ClassSubjectResource\Pages;
use App\Filament\Resources\ClassSubjectResource;
use App\Models\ClassSubject;
use Filament\Actions;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\CreateRecord;
class CreateClassSubject extends CreateRecord
{
protected static string $resource = ClassSubjectResource::class;
protected function mutateFormDataBeforeCreate(array $data): array
{
$exists = ClassSubject::where('class_room_id', $data['class_room_id'])
->where('subject_id', $data['subject_id'])
->where('academic_year_id', $data['academic_year_id'])
->exists();
if ($exists) {
Notification::make()
->title('Failed to save')
->body('A record for this class, subject, and academic year combination already exists.')
->danger()
->send();
$this->halt(); // Stop the save process
}
return $data;
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ClassSubjectResource\Pages;
use App\Filament\Resources\ClassSubjectResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditClassSubject extends EditRecord
{
protected static string $resource = ClassSubjectResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ClassSubjectResource\Pages;
use App\Filament\Resources\ClassSubjectResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListClassSubjects extends ListRecords
{
protected static string $resource = ClassSubjectResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@ -2,9 +2,11 @@
namespace App\Filament\Resources;
use App\Filament\Resources\SubjectScopeResource\Pages;
use App\Filament\Resources\SubjectScopeResource\RelationManagers;
use App\Models\SubjectScope;
use App\Filament\Resources\CompetencyAchievementResource\Pages;
use App\Filament\Resources\CompetencyAchievementResource\RelationManagers;
use App\Models\ClassRoom;
use App\Models\CompetencyAchievement;
use App\Models\Subject;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
@ -13,12 +15,10 @@ use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class SubjectScopeResource extends Resource
class CompetencyAchievementResource extends Resource
{
protected static ?string $model = SubjectScope::class;
protected static ?string $model = CompetencyAchievement::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Academic Management';
public static function form(Form $form): Form
@ -27,17 +27,27 @@ class SubjectScopeResource extends Resource
->schema([
Forms\Components\Select::make('subject_id')
->label('Subject')
->options(
fn () => \App\Models\Subject::pluck('name', 'id')->toArray()
)
->searchable()
->required(),
Forms\Components\TextInput::make('religion')
->maxLength(255),
Forms\Components\TextInput::make('learning_goal')
->required()
->maxLength(255),
Forms\Components\Textarea::make('scope')
->options(Subject::pluck('name', 'id')->toArray())
->searchable()
->native(false),
Forms\Components\Select::make('class_room_id')
->label('Class')
->required()
->options(ClassRoom::pluck('class_name', 'id')->toArray())
->searchable()
->native(false),
Forms\Components\TextInput::make('min_score')
->required()
->numeric()
->default(0),
Forms\Components\TextInput::make('max_score')
->required()
->numeric()
->default(0),
Forms\Components\Textarea::make('description')
->required()
->columnSpanFull(),
]);
@ -50,10 +60,15 @@ class SubjectScopeResource extends Resource
Tables\Columns\TextColumn::make('subject.name')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('religion')
->searchable(),
Tables\Columns\TextColumn::make('learning_goal')
->searchable(),
Tables\Columns\TextColumn::make('classRoom.class_name')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('min_score')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('max_score')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
@ -68,11 +83,15 @@ class SubjectScopeResource extends Resource
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\ViewAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
])
->emptyStateActions([
Tables\Actions\CreateAction::make(),
]);
}
@ -86,9 +105,9 @@ class SubjectScopeResource extends Resource
public static function getPages(): array
{
return [
'index' => Pages\ListSubjectScopes::route('/'),
'create' => Pages\CreateSubjectScope::route('/create'),
'edit' => Pages\EditSubjectScope::route('/{record}/edit'),
'index' => Pages\ListCompetencyAchievements::route('/'),
'create' => Pages\CreateCompetencyAchievement::route('/create'),
'edit' => Pages\EditCompetencyAchievement::route('/{record}/edit'),
];
}
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\CompetencyAchievementResource\Pages;
use App\Filament\Resources\CompetencyAchievementResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateCompetencyAchievement extends CreateRecord
{
protected static string $resource = CompetencyAchievementResource::class;
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\CompetencyAchievementResource\Pages;
use App\Filament\Resources\CompetencyAchievementResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditCompetencyAchievement extends EditRecord
{
protected static string $resource = CompetencyAchievementResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\CompetencyAchievementResource\Pages;
use App\Filament\Resources\CompetencyAchievementResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListCompetencyAchievements extends ListRecords
{
protected static string $resource = CompetencyAchievementResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@ -56,18 +56,21 @@ class ExtracurricularResource extends Resource
// Tambahkan filter jika perlu
])
->actions([
Tables\Actions\EditAction::make()->label('Edit'),
Tables\Actions\DeleteAction::make()->label('Hapus'),
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\DeleteBulkAction::make()->label('Hapus Massal'),
Tables\Actions\DeleteBulkAction::make(),
])
->emptyStateActions([
Tables\Actions\CreateAction::make(),
]);
}
public static function getRelations(): array
{
return [
// Tambahkan RelationManager jika ada
//
];
}

View File

@ -0,0 +1,109 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\HomeRoomTeacherResource\Pages;
use App\Filament\Resources\HomeRoomTeacherResource\RelationManagers;
use App\Models\AcademicYear;
use App\Models\ClassRoom;
use App\Models\HomeRoomTeacher;
use App\Models\User;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class HomeRoomTeacherResource extends Resource
{
protected static ?string $model = HomeRoomTeacher::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('class_room_id')
->label('Class Room')
->required()
->options(ClassRoom::pluck('class_name', 'id')->toArray())
->searchable()
->native(false),
Forms\Components\Select::make('teacher_id')
->label('Teacher')
->required()
->options(User::role('teacher')->pluck('name', 'id')->toArray())
->searchable()
->native(false),
Forms\Components\Select::make('academic_year_id')
->label('Academic Year')
->required()
->options(AcademicYear::pluck('name', 'id')->toArray())
->searchable()
->native(false),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('classRoom.class_name')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('teacher.name')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('academicYear.name')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
])
->emptyStateActions([
Tables\Actions\CreateAction::make(),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListHomeRoomTeachers::route('/'),
'create' => Pages\CreateHomeRoomTeacher::route('/create'),
'edit' => Pages\EditHomeRoomTeacher::route('/{record}/edit'),
];
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace App\Filament\Resources\HomeRoomTeacherResource\Pages;
use App\Filament\Resources\HomeRoomTeacherResource;
use App\Models\ClassStudent;
use App\Models\HomeRoomTeacher;
use Filament\Actions;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\CreateRecord;
class CreateHomeRoomTeacher extends CreateRecord
{
protected static string $resource = HomeRoomTeacherResource::class;
protected function mutateFormDataBeforeCreate(array $data): array
{
$exists = HomeRoomTeacher::where('class_room_id', $data['class_room_id'])
->where('teacher_id', $data['teacher_id'])
->where('academic_year_id', $data['academic_year_id'])
->exists();
if ($exists) {
Notification::make()
->title('Failed to save')
->body('A record for this class room, teacher, and academic year combination already exists.')
->danger()
->send();
$this->halt(); // Stop the save process
}
return $data;
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace App\Filament\Resources\HomeRoomTeacherResource\Pages;
use App\Filament\Resources\HomeRoomTeacherResource;
use App\Models\ClassStudent;
use App\Models\HomeRoomTeacher;
use Filament\Actions;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\EditRecord;
class EditHomeRoomTeacher extends EditRecord
{
protected static string $resource = HomeRoomTeacherResource::class;
protected function mutateFormDataBeforeSave(array $data): array
{
$exists = HomeRoomTeacher::where('class_room_id', $data['class_room_id'])
->where('teacher_id', $data['teacher_id'])
->where('academic_year_id', $data['academic_year_id'])
->exists();
if ($exists) {
Notification::make()
->title('Failed to save')
->body('A record for this class room, teacher, and academic year combination already exists.')
->danger()
->send();
$this->halt(); // Stop the save process
}
return $data;
}
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\HomeRoomTeacherResource\Pages;
use App\Filament\Resources\HomeRoomTeacherResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListHomeRoomTeachers extends ListRecords
{
protected static string $resource = HomeRoomTeacherResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@ -18,14 +18,18 @@ class StudentResource extends Resource
protected static ?string $navigationIcon = 'heroicon-o-users';
protected static ?string $navigationGroup = 'Academic Management';
protected static ?string $navigationGroup = 'Data Master';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Section::make('Informasi Siswa')
Forms\Components\Section::make('Data Siswa')
->schema([
Forms\Components\TextInput::make('nisn')
->label('NISN')
->maxLength(20),
Forms\Components\TextInput::make('nis')
->label('NIS')
->required()
@ -62,14 +66,6 @@ class StudentResource extends Resource
->email()
->maxLength(100),
Forms\Components\Select::make('class_id')
->label('Class')
->options(
fn () => \App\Models\ClassRoom::pluck('class_name', 'id')->toArray()
)
->searchable()
->required(),
Forms\Components\TextInput::make('parent_name')
->label("Parent's Name")
->required()
@ -79,9 +75,19 @@ class StudentResource extends Resource
->label("Parent's Phone")
->maxLength(15),
Forms\Components\Select::make('religion')
->label('Religion')
->options([
'islam' => 'Islam',
'hindu' => 'Hindu',
'katolik' => 'Katolik',
'kristen' => 'Kristen',
'buddha' => 'Buddha',
]),
Forms\Components\Textarea::make('address')
->label('Address')
->rows(3),
->rows(1),
])
->columns(2),
@ -107,12 +113,12 @@ class StudentResource extends Resource
Tables\Columns\TextColumn::make('birth_date')
->label('Birth Date')
->date(),
Tables\Columns\TextColumn::make('classRoom.class_name')
->label('Class')
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('parent_name')
->label("Parent's Name"),
Tables\Columns\TextColumn::make('religion')
->label("Religion")
->formatStateUsing(fn (string $state): string => strtoupper($state))
->badge(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
@ -129,6 +135,9 @@ class StudentResource extends Resource
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
])
->emptyStateActions([
Tables\Actions\CreateAction::make(),
]);
}

View File

@ -28,8 +28,18 @@ class SubjectResource extends Resource
Forms\Components\TextInput::make('name')
->required()
->maxLength(255),
Forms\Components\Toggle::make('is_religious')
->required(),
Forms\Components\Select::make('category')
->options([
'umum' => 'Umum',
'muatan lokal' => 'Muatan Lokal',
'seni' => 'Seni',
])
->required(),
]);
}
@ -38,9 +48,14 @@ class SubjectResource extends Resource
return $table
->columns([
Tables\Columns\TextColumn::make('name')
->label("Name")
->searchable(),
Tables\Columns\IconColumn::make('is_religious')
->label("Is Religious")
->boolean(),
Tables\Columns\TextColumn::make('category')
->label("Category")
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
@ -60,6 +75,9 @@ class SubjectResource extends Resource
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
])
->emptyStateActions([
Tables\Actions\CreateAction::make(),
]);
}

View File

@ -1,12 +0,0 @@
<?php
namespace App\Filament\Resources\SubjectScopeResource\Pages;
use App\Filament\Resources\SubjectScopeResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateSubjectScope extends CreateRecord
{
protected static string $resource = SubjectScopeResource::class;
}

View File

@ -1,19 +0,0 @@
<?php
namespace App\Filament\Resources\SubjectScopeResource\Pages;
use App\Filament\Resources\SubjectScopeResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditSubjectScope extends EditRecord
{
protected static string $resource = SubjectScopeResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@ -1,19 +0,0 @@
<?php
namespace App\Filament\Resources\SubjectScopeResource\Pages;
use App\Filament\Resources\SubjectScopeResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListSubjectScopes extends ListRecords
{
protected static string $resource = SubjectScopeResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@ -3,6 +3,7 @@
namespace App\Filament\Resources;
use App\Filament\Resources\TeacherSubjectResource\Pages;
use App\Models\AcademicYear;
use App\Models\ClassRoom;
use App\Models\Subject;
use App\Models\TeacherSubject;
@ -50,11 +51,12 @@ class TeacherSubjectResource extends Resource
->searchable()
->native(false),
Forms\Components\TextInput::make('academic_year')
Forms\Components\Select::make('academic_year_id')
->label('Academic Year')
->required()
->placeholder('e.g. 2023/2024')
->maxLength(9),
->options(AcademicYear::pluck('name', 'id')->toArray())
->searchable()
->native(false),
])
->columns(2),
@ -80,7 +82,7 @@ class TeacherSubjectResource extends Resource
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('academic_year')
Tables\Columns\TextColumn::make('academicYear.name')
->label('Academic Year')
->searchable()
->sortable(),

View File

@ -17,7 +17,7 @@ class CreateTeacherSubject extends CreateRecord
$exists = TeacherSubject::where('teacher_id', $data['teacher_id'])
->where('subject_id', $data['subject_id'])
->where('class_id', $data['class_id'])
->where('academic_year', $data['academic_year'])
->where('academic_year_id', $data['academic_year_id'])
->exists();
if ($exists) {

View File

@ -73,8 +73,11 @@ class UserResource extends Resource
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
// Tables\Actions\DeleteBulkAction::make(),
]),
])
->emptyStateActions([
Tables\Actions\CreateAction::make(),
]);
}

View File

@ -0,0 +1,34 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
class AcademicYear extends Model
{
use SoftDeletes;
protected $fillable = ['name', 'is_active', 'start_date', 'end_date'];
public function homeRoomTeahcer(): HasMany
{
return $this->hasMany(HomeRoomTeacher::class);
}
public function teacherSubject(): HasMany
{
return $this->hasMany(TeacherSubject::class, 'academic_year_id');
}
public function classStudents()
{
return $this->hasMany(ClassStudent::class);
}
public function classSubjects()
{
return $this->hasMany(ClassStudent::class);
}
}

View File

@ -10,6 +10,7 @@ class Assessment extends Model
'teacher_subject_id',
'student_id',
'score',
'semester'
];
public function teacherSubject()

View File

@ -4,28 +4,44 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
class ClassRoom extends Model
{
use SoftDeletes;
protected $fillable = [
'class_name',
'class_level',
'homeroom_teacher_id',
'academic_year'
];
public function homeroomTeacher()
{
return $this->belongsTo(User::class, 'homeroom_teacher_id');
return $this->hasMany(HomeRoomTeacher::class);
}
public function students()
{
return $this->hasMany(Student::class, 'class_id');
return $this->hasMany(Student::class);
}
public function teacherAssignments(): HasMany
{
return $this->hasMany(TeacherSubject::class, 'class_id');
return $this->hasMany(TeacherSubject::class);
}
public function competencyAchievements()
{
return $this->hasMany(CompetencyAchievement::class);
}
public function classStudents()
{
return $this->hasMany(ClassStudent::class);
}
public function classSubjects(): HasMany
{
return $this->hasMany(ClassSubject::class);
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class ClassStudent extends Model
{
use SoftDeletes;
protected $fillable = ['class_room_id', 'student_id', 'academic_year_id'];
public function class()
{
return $this->belongsTo(ClassRoom::class, 'class_room_id');
}
public function student()
{
return $this->belongsTo(Student::class, 'student_id');
}
public function academicYear()
{
return $this->belongsTo(AcademicYear::class, 'academic_year_id');
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class ClassSubject extends Model
{
protected $fillable = ['class_room_id', 'subject_id', 'academic_year_id'];
public function subject(): BelongsTo
{
return $this->belongsTo(Subject::class, 'subject_id');
}
public function class(): BelongsTo
{
return $this->belongsTo(ClassRoom::class, 'class_room_id');
}
public function academicYear(): BelongsTo
{
return $this->belongsTo(AcademicYear::class, 'academic_year_id');
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class CompetencyAchievement extends Model
{
use SoftDeletes;
protected $fillable = [
'subject_id',
'class_room_id',
'min_score',
'max_score',
'description',
];
// Relasi ke Subject
public function subject()
{
return $this->belongsTo(Subject::class, 'subject_id');
}
// Relasi ke ClassRoom
public function classRoom()
{
return $this->belongsTo(ClassRoom::class, 'class_room_id');
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class HomeRoomTeacher extends Model
{
use SoftDeletes;
protected $fillable = ['class_room_id', 'teacher_id', 'academic_year_id'];
public function classRoom()
{
return $this->belongsTo(ClassRoom::class, 'class_room_id');
}
public function teacher()
{
return $this->belongsTo(User::class, 'teacher_id');
}
public function academicYear()
{
return $this->belongsTo(AcademicYear::class, 'academic_year_id');
}
}

View File

@ -17,18 +17,17 @@ class Student extends Model
'religion',
'phone',
'email',
'class_id',
'parent_name',
'parent_phone',
'is_active',
];
protected $casts = [
'birth_date' => 'date',
];
// Relasi dengan kelas
public function classRoom()
public function classStudents()
{
return $this->belongsTo(ClassRoom::class, 'class_id');
return $this->hasMany(ClassStudent::class);
}
}

View File

@ -7,7 +7,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
class Subject extends Model
{
protected $fillable = ['name', 'is_religious'];
protected $fillable = ['name', 'is_religious', 'category'];
public function scopes()
{
@ -16,12 +16,16 @@ class Subject extends Model
public function teacherAssignments(): HasMany
{
return $this->hasMany(TeacherSubject::class, 'subject_id');
return $this->hasMany(TeacherSubject::class);
}
public function competencyAchievements()
{
return $this->hasMany(CompetencyAchievement::class);
}
// public function grades()
// {
// return $this->hasMany(Grade::class);
// }
public function classSubjects(): HasMany
{
return $this->hasMany(ClassSubject::class);
}
}

View File

@ -1,15 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class SubjectScope extends Model
{
protected $fillable = ['subject_id', 'religion', 'learning_goal', 'scope'];
public function subject()
{
return $this->belongsTo(Subject::class);
}
}

View File

@ -4,53 +4,34 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class TeacherSubject extends Model
{
protected $fillable = ['teacher_id', 'subject_id', 'class_id', 'academic_year'];
protected $fillable = ['teacher_id', 'subject_id', 'class_id', 'academic_year_id'];
/**
* Get the teacher associated with this assignment
*/
public function teacher(): BelongsTo
{
return $this->belongsTo(User::class, 'teacher_id');
}
/**
* Get the subject associated with this assignment
*/
public function subject(): BelongsTo
{
return $this->belongsTo(Subject::class, 'subject_id');
}
/**
* Get the class associated with this assignment
*/
public function class(): BelongsTo
{
return $this->belongsTo(ClassRoom::class, 'class_id');
}
/**
* Scope for current academic year
*/
public function scopeCurrentYear($query)
{
return $query->where('academic_year', now()->format('Y'));
}
/**
* Scope for specific academic year
*/
public function scopeForYear($query, $year)
{
return $query->where('academic_year', $year);
}
public function attendances()
{
return $this->hasMany(Attendances::class);
}
public function academicYear() : BelongsTo
{
return $this->belongsTo(AcademicYear::class, 'academic_year_id');
}
}

View File

@ -57,4 +57,9 @@ class User extends Authenticatable
{
return $this->hasMany(TeacherSubject::class, 'teacher_id');
}
public function homeRoomTeacher(): HasMany
{
return $this->hasMany(HomeRoomTeacher::class, 'teacher_id');
}
}

View File

@ -12,7 +12,7 @@ class SubjectScopePolicy
*/
public function viewAny(User $user): bool
{
return $user->can('view_any_subject_scope');
return $user->can('view_any_subject::scope');
}
/**
@ -20,7 +20,7 @@ class SubjectScopePolicy
*/
public function view(User $user, SubjectScope $subjectScope): bool
{
return $user->can('view_subject_scope');
return $user->can('view_subject::scope');
}
/**
@ -28,7 +28,7 @@ class SubjectScopePolicy
*/
public function create(User $user): bool
{
return $user->can('create_subject_scope');
return $user->can('create_subject::scope');
}
/**
@ -36,7 +36,7 @@ class SubjectScopePolicy
*/
public function update(User $user, SubjectScope $subjectScope): bool
{
return $user->can('update_subject_scope');
return $user->can('update_subject::scope');
}
/**
@ -44,7 +44,7 @@ class SubjectScopePolicy
*/
public function delete(User $user, SubjectScope $subjectScope): bool
{
return $user->can('delete_subject_scope');
return $user->can('delete_subject::scope');
}
/**
@ -52,7 +52,7 @@ class SubjectScopePolicy
*/
public function restore(User $user, SubjectScope $subjectScope): bool
{
return $user->can('restore_subject_scope');
return $user->can('restore_subject::scope');
}
/**
@ -60,6 +60,6 @@ class SubjectScopePolicy
*/
public function forceDelete(User $user, SubjectScope $subjectScope): bool
{
return $user->can('force_delete_subject_scope');
return $user->can('force_delete_subject::scope');
}
}

View File

@ -12,7 +12,7 @@ class TeacherSubjectPolicy
*/
public function viewAny(User $user): bool
{
return $user->can('view_any_teacher_subject');
return $user->can('view_any_teacher::subject');
}
/**
@ -20,7 +20,7 @@ class TeacherSubjectPolicy
*/
public function view(User $user, TeacherSubject $teacherSubject): bool
{
return $user->can('view_teacher_subject');
return $user->can('view_teacher::subject');
}
/**
@ -28,7 +28,7 @@ class TeacherSubjectPolicy
*/
public function create(User $user): bool
{
return $user->can('create_teacher_subject');
return $user->can('create_teacher::subject');
}
/**
@ -36,7 +36,7 @@ class TeacherSubjectPolicy
*/
public function update(User $user, TeacherSubject $teacherSubject): bool
{
return $user->can('update_teacher_subject');
return $user->can('update_teacher::subject');
}
/**
@ -44,7 +44,7 @@ class TeacherSubjectPolicy
*/
public function delete(User $user, TeacherSubject $teacherSubject): bool
{
return $user->can('delete_teacher_subject');
return $user->can('delete_teacher::subject');
}
/**
@ -52,7 +52,7 @@ class TeacherSubjectPolicy
*/
public function restore(User $user, TeacherSubject $teacherSubject): bool
{
return $user->can('restore_teacher_subject');
return $user->can('restore_teacher::subject');
}
/**
@ -60,6 +60,6 @@ class TeacherSubjectPolicy
*/
public function forceDelete(User $user, TeacherSubject $teacherSubject): bool
{
return $user->can('force_delete_teacher_subject');
return $user->can('force_delete_teacher::subject');
}
}

View File

@ -15,9 +15,10 @@ return new class extends Migration
$table->id();
$table->string('class_name');
$table->string('class_level');
$table->foreignId('homeroom_teacher_id')->nullable()->constrained('users');
$table->string('academic_year');
$table->timestamps();
$table->softDeletes();
$table->unique(['class_name', 'class_level']);
});
}

View File

@ -23,10 +23,13 @@ return new class extends Migration
$table->text('religion')->nullable();
$table->string('phone')->nullable();
$table->string('email')->nullable();
$table->foreignId('class_id')->nullable()->constrained('class_rooms');
$table->string('parent_name')->nullable();
$table->string('parent_phone')->nullable();
$table->boolean('is_active')->default(true);
$table->timestamps();
$table->softDeletes();
$table->unique(['nis', 'nisn']);
});
}

View File

@ -11,13 +11,16 @@ return new class extends Migration
*/
public function up(): void
{
Schema::create('subject_scopes', function (Blueprint $table) {
Schema::create('academic_years', function (Blueprint $table) {
$table->id();
$table->foreignId('subject_id')->constrained()->onDelete('cascade');
$table->string('religion')->nullable(); // null jika bukan mapel agama
$table->string('learning_goal');
$table->text('scope');
$table->string('name'); // contoh: 2024/2025
$table->boolean('is_active')->default(false);
$table->date('start_date')->nullable();
$table->date('end_date')->nullable();
$table->timestamps();
$table->softDeletes();
$table->unique(['name']);
});
}
@ -26,6 +29,6 @@ return new class extends Migration
*/
public function down(): void
{
Schema::dropIfExists('subject_scopes');
Schema::dropIfExists('academic_years');
}
};

View File

@ -15,7 +15,10 @@ return new class extends Migration
$table->id();
$table->string('name');
$table->boolean('is_religious')->default(false);
$table->enum('category', ['umum', 'muatan lokal', 'seni']);
$table->timestamps();
$table->unique(['name', 'is_religious', 'category']);
});
}

View File

@ -16,10 +16,10 @@ return new class extends Migration
$table->foreignId('teacher_id')->constrained('users');
$table->foreignId('subject_id')->constrained('subjects');
$table->foreignId('class_id')->constrained('class_rooms');
$table->string('academic_year');
$table->foreignId('academic_year_id')->constrained('academic_years');
$table->timestamps();
$table->unique(['teacher_id', 'subject_id', 'class_id', 'academic_year']);
$table->unique(['teacher_id', 'subject_id', 'class_id', 'academic_year_id']);
});
}

View File

@ -16,9 +16,10 @@ return new class extends Migration
$table->foreignId('teacher_subject_id')->constrained('teacher_subjects');
$table->foreignId('student_id')->constrained('students');
$table->float('score');
$table->string('semester');
$table->timestamps();
$table->unique(['teacher_subject_id', 'student_id']);
$table->unique(['teacher_subject_id', 'student_id', 'semester']);
});
}

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('competency_achievements', function (Blueprint $table) {
$table->id();
$table->foreignId('subject_id')->constrained('subjects');
$table->foreignId('class_room_id')->constrained('class_rooms');
$table->float("min_score")->default(0);
$table->float("max_score")->default(0);
$table->text("description");
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('competency_achievements');
}
};

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('home_room_teachers', function (Blueprint $table) {
$table->id();
$table->foreignId('class_room_id')->constrained('class_rooms');
$table->foreignId('teacher_id')->constrained('users');
$table->foreignId('academic_year_id')->constrained('academic_years');
$table->timestamps();
$table->unique(['class_room_id', 'teacher_id', 'academic_year_id']);
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('home_room_teachers');
}
};

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('class_students', function (Blueprint $table) {
$table->id();
$table->foreignId('class_room_id')->constrained('class_rooms');
$table->foreignId('student_id')->constrained('students');
$table->foreignId('academic_year_id')->constrained('academic_years');
$table->timestamps();
$table->unique(['class_room_id', 'student_id', 'academic_year_id']);
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('class_students');
}
};

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('class_subjects', function (Blueprint $table) {
$table->id();
$table->foreignId('class_room_id')->constrained('class_rooms');
$table->foreignId('subject_id')->constrained('subjects');
$table->foreignId('academic_year_id')->constrained('academic_years');
$table->timestamps();
$table->softDeletes();
$table->unique(['class_room_id', 'subject_id', 'academic_year_id']);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('class_subjects');
}
};

View File

@ -0,0 +1,36 @@
<?php
namespace Database\Seeders;
use Carbon\Carbon;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class AcademicYearSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
DB::table('academic_years')->insert([
[
'name' => '2023/2024',
'is_active' => false,
'start_date' => Carbon::create(2023, 7, 1),
'end_date' => Carbon::create(2024, 6, 30),
'created_at' => now(),
'updated_at' => now(),
],
[
'name' => '2024/2025',
'is_active' => true,
'start_date' => Carbon::create(2024, 7, 1),
'end_date' => Carbon::create(2025, 6, 30),
'created_at' => now(),
'updated_at' => now(),
],
]);
}
}

View File

@ -1,17 +0,0 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class AttendanceSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
//
}
}

View File

@ -18,14 +18,13 @@ class ClassRoomSeeder extends Seeder
$teachers = User::role('teacher')->get();
$classes = [
['class_name' => '1 A', 'class_level' => '1', 'academic_year' => '2024/2025'],
['class_name' => '1 B', 'class_level' => '1', 'academic_year' => '2024/2025'],
['class_name' => '2 A', 'class_level' => '2', 'academic_year' => '2024/2025'],
['class_name' => '2 B', 'class_level' => '2', 'academic_year' => '2024/2025'],
['class_name' => '1 A', 'class_level' => '1'],
['class_name' => '1 B', 'class_level' => '1'],
['class_name' => '2 A', 'class_level' => '2'],
['class_name' => '2 B', 'class_level' => '2'],
];
foreach ($classes as $index => $class) {
$class['homeroom_teacher_id'] = $teachers[$index % count($teachers)]->id;
ClassRoom::create($class);
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace Database\Seeders;
use App\Models\AcademicYear;
use App\Models\ClassRoom;
use App\Models\ClassStudent;
use App\Models\Student;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class ClassStudentSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
// Pastikan data ClassRoom, Student, dan AcademicYear sudah ada
$classRooms = ClassRoom::all();
$students = Student::all();
$academicYears = AcademicYear::all();
// Hanya melanjutkan jika data tersedia
if ($classRooms->isNotEmpty() && $students->isNotEmpty() && $academicYears->isNotEmpty()) {
foreach ($classRooms as $classRoom) {
foreach ($students as $student) {
foreach ($academicYears as $academicYear) {
// Buat ClassStudent baru untuk setiap kombinasi
ClassStudent::create([
'class_room_id' => $classRoom->id,
'student_id' => $student->id,
'academic_year_id' => $academicYear->id,
]);
}
}
}
}
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace Database\Seeders;
use App\Models\AcademicYear;
use App\Models\ClassRoom;
use App\Models\ClassSubject;
use App\Models\Subject;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class ClassSubjectSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$classRooms = ClassRoom::all();
$subjects = Subject::all();
$academicYear = AcademicYear::where('is_active', true)->first();
if (!$academicYear) {
$this->command->error('Tahun ajaran aktif tidak ditemukan.');
return;
}
foreach ($classRooms as $classRoom) {
// Contoh: ambil 3 sampai 5 mapel random untuk tiap kelas
$assignedSubjects = $subjects->random(rand(3, 5));
foreach ($assignedSubjects as $subject) {
ClassSubject::firstOrCreate([
'class_room_id' => $classRoom->id,
'subject_id' => $subject->id,
'academic_year_id' => $academicYear->id,
]);
}
}
}
}

View File

@ -2,11 +2,7 @@
namespace Database\Seeders;
use App\Models\ClassRoom;
use App\Models\User;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
class DatabaseSeeder extends Seeder
{
@ -19,9 +15,12 @@ class DatabaseSeeder extends Seeder
UserSeeder::class,
SubjectSeeder::class,
ClassRoomSeeder::class,
AcademicYearSeeder::class,
StudentSeeder::class,
ExtracurricularSeeder::class,
AttendanceSeeder::class,
ClassSubjectSeeder::class,
ClassStudentSeeder::class,
HomeRoomTeacherSeeder::class,
]);
}
}

View File

@ -2,10 +2,14 @@
namespace Database\Seeders;
use App\Models\AcademicYear;
use App\Models\ClassRoom;
use App\Models\HomeRoomTeacher;
use App\Models\User;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class SubjectScopeSeeder extends Seeder
class HomeRoomTeacherSeeder extends Seeder
{
/**
* Run the database seeds.
@ -14,4 +18,5 @@ class SubjectScopeSeeder extends Seeder
{
}
}

View File

@ -4,6 +4,7 @@ namespace Database\Seeders;
use App\Models\ClassRoom;
use App\Models\Student;
use Carbon\Carbon;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
@ -14,31 +15,29 @@ class StudentSeeder extends Seeder
*/
public function run(): void
{
$classrooms = ClassRoom::all();
$religions = ['islam', 'kristen', 'katolik', 'hindu', 'buddha'];
foreach ($classrooms as $classroom) {
for ($i = 1; $i <= 20; $i++) {
$gender = $i % 2 == 0 ? 'L' : 'P';
$religion = $religions[array_rand($religions)];
$nis = $classroom->class_level . str_pad($i, 3, '0', STR_PAD_LEFT);
$nis = '24' . str_pad($i, 4, '0', STR_PAD_LEFT); // NIS unik, misal 240001
Student::firstOrCreate(
['nis' => $nis], // Cek berdasarkan NIS
[
'full_name' => 'Siswa ' . $classroom->class_name . ' ' . $i,
'full_name' => 'Siswa ' . $i,
'gender' => $gender,
'birth_date' => now()->subYears(rand(15, 18))->subMonths(rand(1, 12)),
'birth_date' => Carbon::now()->subYears(rand(15, 18))->subMonths(rand(1, 12)),
'birth_place' => 'Kota ' . chr(65 + rand(0, 25)),
'address' => 'Jl. Contoh No.' . $i,
'phone' => '0812' . rand(1000000, 9999999),
'class_id' => $classroom->id,
'parent_name' => 'Orang Tua Siswa ' . $i,
'religion' => $religion,
'parent_phone' => '0813' . rand(1000000, 9999999),
'created_at' => now(),
'updated_at' => now(),
]
);
}
}
}
}

View File

@ -3,7 +3,6 @@
namespace Database\Seeders;
use App\Models\Subject;
use App\Models\SubjectScope;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
@ -15,16 +14,21 @@ class SubjectSeeder extends Seeder
public function run(): void
{
$subjects = [
['name' => 'Matematika', 'is_religious' => false],
['name' => 'Bahasa Indonesia', 'is_religious' => false],
['name' => 'Bahasa Inggris', 'is_religious' => false],
['name' => 'IPA', 'is_religious' => false],
['name' => 'IPS', 'is_religious' => false],
['name' => 'Pendidikan Agama Islam', 'is_religious' => true],
['name' => 'Pendidikan Agama Kristen', 'is_religious' => true],
['name' => 'Pendidikan Agama Katolik', 'is_religious' => true],
['name' => 'Pendidikan Agama Hindu', 'is_religious' => true],
['name' => 'Pendidikan Agama Buddha', 'is_religious' => true],
['name' => 'Matematika', 'is_religious' => false, 'category' => 'umum'],
['name' => 'Bahasa Indonesia', 'is_religious' => false, 'category' => 'umum'],
['name' => 'Bahasa Inggris', 'is_religious' => false, 'category' => 'umum'],
['name' => 'IPA', 'is_religious' => false, 'category' => 'umum'],
['name' => 'IPS', 'is_religious' => false, 'category' => 'umum'],
['name' => 'Seni Rupa', 'is_religious' => false, 'category' => 'seni'],
['name' => 'Seni Musik', 'is_religious' => false, 'category' => 'seni'],
['name' => 'Seni Tari', 'is_religious' => false, 'category' => 'seni'],
['name' => 'Seni Teater', 'is_religious' => false, 'category' => 'seni'],
['name' => 'Bahasa Sunda', 'is_religious' => false, 'category' => 'muatan lokal'],
['name' => 'Pendidikan Agama Islam', 'is_religious' => true, 'category' => 'umum'],
['name' => 'Pendidikan Agama Kristen', 'is_religious' => true, 'category' => 'umum'],
['name' => 'Pendidikan Agama Katolik', 'is_religious' => true, 'category' => 'umum'],
['name' => 'Pendidikan Agama Hindu', 'is_religious' => true, 'category' => 'umum'],
['name' => 'Pendidikan Agama Buddha', 'is_religious' => true, 'category' => 'umum'],
];
foreach ($subjects as $subject) {
@ -40,15 +44,6 @@ class SubjectSeeder extends Seeder
str_contains($createdSubject->name, 'Buddha') => 'buddha',
default => null
};
if ($religion) {
SubjectScope::create([
'subject_id' => $createdSubject->id,
'religion' => $religion,
'learning_goal' => 'Memahami prinsip dasar agama ' . $religion,
'scope' => 'Tingkat dasar'
]);
}
}
}
}

View File

@ -0,0 +1,77 @@
<x-filament-panels::page>
{{ $this->form }}
@if(!empty($this->list))
<div class="fi-ta-ctn overflow-hidden rounded-lg bg-white shadow-sm ring-1 ring-gray-200 dark:bg-gray-900 dark:ring-gray-800">
<div class="fi-ta-content overflow-x-auto">
<table class="fi-ta-table w-full border-collapse">
<thead class="bg-gray-50 dark:bg-gray-800">
<!-- Baris Judul Kelompok -->
<tr>
<th rowspan="2" class="fi-ta-header-cell px-4 py-3 text-left border-b border-gray-200 dark:border-gray-700">
<span class="text-sm font-medium text-gray-900 dark:text-white">
{{ $this->list['header']['name'] }}
</span>
</th>
@foreach(['umum', 'muatan lokal'] as $category)
@if(!empty($this->list['header'][$category]))
<th colspan="{{ count($this->list['header'][$category]) }}" class="fi-ta-header-cell px-4 py-3 text-center border-b border-gray-200 dark:border-gray-700">
<span class="text-sm font-medium text-gray-900 dark:text-white">
{{ ucfirst($category) }}
</span>
</th>
@endif
@endforeach
</tr>
<!-- Baris Mata Pelajaran -->
<tr>
@foreach(['umum', 'muatan lokal'] as $category)
@if(!empty($this->list['header'][$category]))
@foreach($this->list['header'][$category] as $subjectName)
<th class="fi-ta-header-cell px-4 py-3 text-center border-b border-gray-200 dark:border-gray-700">
<span class="text-sm font-medium text-gray-900 dark:text-white">
{{ $subjectName }}
</span>
</th>
@endforeach
@endif
@endforeach
</tr>
</thead>
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
@foreach($this->list['data'] as $student)
<tr class="hover:bg-gray-50 dark:hover:bg-gray-800/50">
<!-- Kolom Nama -->
<td class="fi-ta-cell px-4 py-3 border-b border-gray-200 dark:border-gray-700">
<span class="text-sm text-gray-900 dark:text-white">
{{ $student['name'] }}
</span>
</td>
<!-- Nilai Mata Pelajaran -->
@foreach(['umum', 'muatan lokal'] as $category)
@if(!empty($this->list['header'][$category]))
@foreach($this->list['header'][$category] as $subjectId => $subjectName)
<td class="fi-ta-cell px-4 py-3 text-center border-b border-gray-200 dark:border-gray-700">
<span class="text-sm text-gray-900 dark:text-white">
{{ $student[$category][$subjectId] ?? '-' }}
</span>
</td>
@endforeach
@endif
@endforeach
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
@else
<div class="mt-6 p-4 bg-gray-100 rounded-lg text-gray-600 dark:bg-gray-800 dark:text-gray-300">
Pilih Kelas, Tahun Akademik, dan Semester untuk melihat laporan siswa.
</div>
@endif
</x-filament-panels::page>

View File

@ -10,8 +10,8 @@
@foreach($this->students as $index => $student)
<div class="flex items-center p-3 border rounded-lg">
<div class="flex-1">
<p class="font-medium">{{ $student['name'] }}</p>
<p class="text-sm text-gray-500">{{ $student['nis'] }}</p>
<p class="font-medium">{{ $student['name'] ?? "" }}</p>
<p class="text-sm text-gray-500">{{ $student['nis'] ?? "" }}</p>
</div>
<div class="w-32">
<x-filament::input