add-attendaces
This commit is contained in:
parent
946006cfe6
commit
43344cb74b
235
app/Filament/Resources/AttendancesResource.php
Normal file
235
app/Filament/Resources/AttendancesResource.php
Normal file
@ -0,0 +1,235 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources;
|
||||
|
||||
use App\Filament\Resources\AttendancesResource\Pages;
|
||||
use App\Models\Attendances;
|
||||
use App\Models\ClassRoom;
|
||||
use App\Models\Student;
|
||||
use App\Models\Subject;
|
||||
use App\Models\TeacherSubject;
|
||||
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;
|
||||
|
||||
class AttendancesResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Attendances::class;
|
||||
protected static ?string $navigationIcon = 'heroicon-o-clipboard-document-check';
|
||||
protected static ?string $navigationGroup = 'Student Management';
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
Forms\Components\Section::make('Informasi 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)
|
||||
->searchable()
|
||||
->preload()
|
||||
->columnSpanFull(),
|
||||
|
||||
Forms\Components\DatePicker::make('date')
|
||||
->label('Date')
|
||||
->required()
|
||||
->default(now())
|
||||
->maxDate(now()),
|
||||
|
||||
Forms\Components\Select::make('student_id')
|
||||
->label('Student')
|
||||
->required()
|
||||
->searchable()
|
||||
->options(Student::pluck('full_name', 'id')->toArray())
|
||||
->getOptionLabelUsing(function ($value) {
|
||||
$student = Student::find($value);
|
||||
return $student ? $student->full_name . ' (' . $student->nis . ')' : null;
|
||||
}),
|
||||
|
||||
Forms\Components\Select::make('semester')
|
||||
->label('Semester')
|
||||
->required()
|
||||
->options([
|
||||
'first' => 'First Semester',
|
||||
'second' => 'Second Semester'
|
||||
]),
|
||||
|
||||
Forms\Components\Select::make('status')
|
||||
->label('Status')
|
||||
->required()
|
||||
->options([
|
||||
'present' => 'Present',
|
||||
'absent' => 'Absent',
|
||||
'permission' => 'Permission',
|
||||
'sick' => 'Sick'
|
||||
])
|
||||
->native(false),
|
||||
|
||||
Forms\Components\Hidden::make('recorded_by')
|
||||
->default(auth()->id()),
|
||||
|
||||
Forms\Components\Textarea::make('notes')
|
||||
->label('Notes')
|
||||
->columnSpanFull()
|
||||
])->columns(2)
|
||||
]);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('student.full_name')
|
||||
->label('Student')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('teacherSubject.class.class_name')
|
||||
->label('Class')
|
||||
->searchable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('teacherSubject.subject.name')
|
||||
->label('Subject')
|
||||
->searchable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('teacherSubject.teacher.name')
|
||||
->label('Teacher')
|
||||
->searchable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('date')
|
||||
->label('Date')
|
||||
->date('d/m/Y')
|
||||
->sortable(),
|
||||
|
||||
Tables\Columns\BadgeColumn::make('status')
|
||||
->label('Status')
|
||||
->formatStateUsing(fn (string $state): string => match ($state) {
|
||||
'present' => 'Present',
|
||||
'absent' => 'Absent',
|
||||
'permission' => 'Permission',
|
||||
'sick' => 'Sick'
|
||||
})
|
||||
->color(fn (string $state): string => match ($state) {
|
||||
'present' => 'success',
|
||||
'absent' => 'danger',
|
||||
'permission' => 'warning',
|
||||
'sick' => 'warning'
|
||||
}),
|
||||
|
||||
Tables\Columns\TextColumn::make('semester')
|
||||
->label('Semester')
|
||||
->formatStateUsing(fn (string $state): string => match ($state) {
|
||||
'first' => 'First Semester',
|
||||
'second' => 'Second Semester'
|
||||
}),
|
||||
|
||||
Tables\Columns\TextColumn::make('teacherSubject.academic_year')
|
||||
->label('Academic Year')
|
||||
->searchable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('recorder.name')
|
||||
->label('Record by')
|
||||
->toggleable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('notes')
|
||||
->label('Notes')
|
||||
->toggleable()
|
||||
])
|
||||
->filters([
|
||||
Tables\Filters\SelectFilter::make('status')
|
||||
->label('Status')
|
||||
->options([
|
||||
'present' => 'Present',
|
||||
'absent' => 'Absent',
|
||||
'permission' => 'Permission',
|
||||
'sick' => 'Sick'
|
||||
]),
|
||||
|
||||
Tables\Filters\SelectFilter::make('semester')
|
||||
->label('Semester')
|
||||
->options([
|
||||
'first' => 'First Semester',
|
||||
'second' => 'Second Semester'
|
||||
]),
|
||||
|
||||
Tables\Filters\Filter::make('date')
|
||||
->form([
|
||||
Forms\Components\DatePicker::make('date_from')
|
||||
->label('From'),
|
||||
Forms\Components\DatePicker::make('date_until')
|
||||
->label('To'),
|
||||
])
|
||||
->query(function (Builder $query, array $data): Builder {
|
||||
return $query
|
||||
->when(
|
||||
$data['date_from'],
|
||||
fn (Builder $query, $date): Builder => $query->whereDate('date', '>=', $date),
|
||||
)
|
||||
->when(
|
||||
$data['date_until'],
|
||||
fn (Builder $query, $date): Builder => $query->whereDate('date', '<=', $date),
|
||||
);
|
||||
}),
|
||||
|
||||
Tables\Filters\SelectFilter::make('teacher_subject_id')
|
||||
->label('Teacher Subject')
|
||||
->relationship('teacherSubject', 'id')
|
||||
->searchable()
|
||||
->getOptionLabelFromRecordUsing(fn (TeacherSubject $record) =>
|
||||
$record->teacher->name . ' - ' . $record->subject->name)
|
||||
->preload(),
|
||||
])
|
||||
->actions([
|
||||
Tables\Actions\EditAction::make()
|
||||
->iconButton(),
|
||||
Tables\Actions\DeleteAction::make()
|
||||
->iconButton(),
|
||||
])
|
||||
->bulkActions([
|
||||
Tables\Actions\BulkActionGroup::make([
|
||||
Tables\Actions\DeleteBulkAction::make(),
|
||||
]),
|
||||
])
|
||||
->emptyStateActions([
|
||||
Tables\Actions\CreateAction::make(),
|
||||
])
|
||||
->defaultSort('date', 'desc')
|
||||
->groups([
|
||||
Tables\Grouping\Group::make('date')
|
||||
->label('Date')
|
||||
->date()
|
||||
->collapsible(),
|
||||
Tables\Grouping\Group::make('teacherSubject.subject.name')
|
||||
->label('Subjects')
|
||||
->collapsible(),
|
||||
Tables\Grouping\Group::make('semester')
|
||||
->label('Semester')
|
||||
->collapsible(),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => Pages\ListAttendances::route('/'),
|
||||
'create' => Pages\CreateAttendances::route('/create'),
|
||||
'edit' => Pages\EditAttendances::route('/{record}/edit'),
|
||||
'multiple' => Pages\MultipleAttendances::route('/multiple'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\AttendancesResource\Pages;
|
||||
|
||||
use App\Filament\Resources\AttendancesResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateAttendances extends CreateRecord
|
||||
{
|
||||
protected static string $resource = AttendancesResource::class;
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\AttendancesResource\Pages;
|
||||
|
||||
use App\Filament\Resources\AttendancesResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditAttendances extends EditRecord
|
||||
{
|
||||
protected static string $resource = AttendancesResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\DeleteAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\AttendancesResource\Pages;
|
||||
|
||||
use App\Filament\Resources\AttendancesResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListAttendances extends ListRecords
|
||||
{
|
||||
protected static string $resource = AttendancesResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\CreateAction::make(),
|
||||
Actions\Action::make('multiple')
|
||||
->label('Multiple Attendance')
|
||||
->url('attendances/multiple')
|
||||
->icon('heroicon-o-user-group'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\AttendancesResource\Pages;
|
||||
|
||||
use App\Filament\Resources\AttendancesResource;
|
||||
use App\Models\Attendances;
|
||||
use App\Models\ClassRoom;
|
||||
use App\Models\Student;
|
||||
use App\Models\TeacherSubject;
|
||||
use Filament\Actions;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Resources\Pages\Page;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class MultipleAttendances extends Page
|
||||
{
|
||||
protected static string $resource = AttendancesResource::class;
|
||||
protected static string $view = 'filament.resources.attendances-resource.pages.multiple-attendances';
|
||||
|
||||
public ?array $data = [];
|
||||
public $classroomId;
|
||||
public $teacherSubjectId;
|
||||
|
||||
public $teacherSubject;
|
||||
public $attendanceDate;
|
||||
public $semester = 'first'; // Default semester
|
||||
public $students = [];
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->form->fill([
|
||||
'date' => now()->format('Y-m-d'),
|
||||
'semester' => 'first',
|
||||
]);
|
||||
$this->attendanceDate = now()->format('Y-m-d');
|
||||
}
|
||||
|
||||
public function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
Select::make('teacher_subject_id')
|
||||
->label('Teacher Subject')
|
||||
->required()
|
||||
->options(TeacherSubject::with(['teacher', 'subject', 'class'])
|
||||
->get()
|
||||
->mapWithKeys(fn ($item) => [
|
||||
$item->id => $item->teacher->name . ' - ' . $item->subject->name . ' - ' . $item->class->class_name
|
||||
]))
|
||||
->searchable()
|
||||
->live()
|
||||
->afterStateUpdated(function ($state) {
|
||||
$this->teacherSubjectId = $state;
|
||||
$this->loadStudents();
|
||||
}),
|
||||
|
||||
DatePicker::make('date')
|
||||
->label('Attendance Date')
|
||||
->required()
|
||||
->default(now())
|
||||
->maxDate(now())
|
||||
->live()
|
||||
->afterStateUpdated(function ($state) {
|
||||
$this->attendanceDate = $state;
|
||||
$this->loadStudents();
|
||||
}),
|
||||
|
||||
Select::make('semester')
|
||||
->label('Semester')
|
||||
->required()
|
||||
->options([
|
||||
'first' => 'First Semester',
|
||||
'second' => 'Second Semester'
|
||||
])
|
||||
->live()
|
||||
->afterStateUpdated(function ($state) {
|
||||
$this->semester = $state;
|
||||
$this->loadStudents();
|
||||
}),
|
||||
])
|
||||
->statePath('data');
|
||||
}
|
||||
|
||||
protected function loadStudents(): void
|
||||
{
|
||||
if (!$this->attendanceDate || !$this->teacherSubjectId) {
|
||||
$this->students = [];
|
||||
return;
|
||||
}
|
||||
|
||||
$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) {
|
||||
$existingAttendance = Attendances::where('student_id', $student->id)
|
||||
->where('teacher_subject_id', $this->teacherSubjectId)
|
||||
->whereDate('date', $this->attendanceDate)
|
||||
->where('semester', $this->semester)
|
||||
->first();
|
||||
|
||||
return [
|
||||
'id' => $student->id,
|
||||
'name' => $student->full_name,
|
||||
'nis' => $student->nis,
|
||||
'status' => $existingAttendance ? $existingAttendance->status : null,
|
||||
'attendance_id' => $existingAttendance ? $existingAttendance->id : null,
|
||||
];
|
||||
})
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public function markAll($status): void
|
||||
{
|
||||
foreach ($this->students as $key => $student) {
|
||||
$this->students[$key]['status'] = $status;
|
||||
}
|
||||
}
|
||||
|
||||
public function submit(): void
|
||||
{
|
||||
DB::transaction(function () {
|
||||
foreach ($this->students as $student) {
|
||||
if ($student['status']) {
|
||||
if ($student['attendance_id']) {
|
||||
// Update existing attendance
|
||||
Attendances::where('id', $student['attendance_id'])
|
||||
->update([
|
||||
'status' => $student['status'],
|
||||
'recorded_by' => auth()->id(),
|
||||
]);
|
||||
} else {
|
||||
// Create new attendance
|
||||
Attendances::create([
|
||||
'student_id' => $student['id'],
|
||||
'teacher_subject_id' => $this->teacherSubject->id,
|
||||
'date' => $this->attendanceDate,
|
||||
'status' => $student['status'],
|
||||
'semester' => $this->semester,
|
||||
'recorded_by' => auth()->id(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Notification::make()
|
||||
->title('Attendance saved successfully ' . $this->teacherSubject->id)
|
||||
->success()
|
||||
->send();
|
||||
|
||||
$this->loadStudents();
|
||||
}
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\Action::make('back')
|
||||
->label('Back to Attendances')
|
||||
->url(static::getResource()::getUrl('index')),
|
||||
];
|
||||
}
|
||||
}
|
||||
143
app/Filament/Resources/TeacherSubjectResource.php
Normal file
143
app/Filament/Resources/TeacherSubjectResource.php
Normal file
@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources;
|
||||
|
||||
use App\Filament\Resources\TeacherSubjectResource\Pages;
|
||||
use App\Models\ClassRoom;
|
||||
use App\Models\Subject;
|
||||
use App\Models\TeacherSubject;
|
||||
use App\Models\User;
|
||||
use Closure;
|
||||
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\Support\Str;
|
||||
|
||||
class TeacherSubjectResource extends Resource
|
||||
{
|
||||
protected static ?string $model = TeacherSubject::class;
|
||||
|
||||
protected static ?string $navigationIcon = 'heroicon-o-academic-cap';
|
||||
protected static ?string $navigationGroup = 'Academic Management';
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
Forms\Components\Section::make('Teacher Subject Assignment')
|
||||
->schema([
|
||||
Forms\Components\Select::make('teacher_id')
|
||||
->label('Teacher')
|
||||
->required()
|
||||
->options(User::role('teacher')->pluck('name', 'id')->toArray())
|
||||
->searchable()
|
||||
->native(false),
|
||||
|
||||
Forms\Components\Select::make('subject_id')
|
||||
->label('Subject')
|
||||
->required()
|
||||
->options(Subject::pluck('name', 'id')->toArray())
|
||||
->searchable()
|
||||
->native(false),
|
||||
|
||||
Forms\Components\Select::make('class_id')
|
||||
->label('Class')
|
||||
->required()
|
||||
->options(ClassRoom::pluck('class_name', 'id')->toArray())
|
||||
->searchable()
|
||||
->native(false),
|
||||
|
||||
Forms\Components\TextInput::make('academic_year')
|
||||
->label('Academic Year')
|
||||
->required()
|
||||
->placeholder('e.g. 2023/2024')
|
||||
->maxLength(9),
|
||||
|
||||
])
|
||||
->columns(2),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('teacher.name')
|
||||
->label('Teacher')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('subject.name')
|
||||
->label('Subject')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('class.class_name')
|
||||
->label('Class')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('academic_year')
|
||||
->label('Academic Year')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
Tables\Columns\TextColumn::make('created_at')
|
||||
->label('Assigned At')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
Tables\Filters\SelectFilter::make('teacher_id')
|
||||
->label('Teacher')
|
||||
->relationship('teacher', 'name')
|
||||
->searchable()
|
||||
->preload(),
|
||||
|
||||
Tables\Filters\SelectFilter::make('subject_id')
|
||||
->label('Subject')
|
||||
->relationship('subject', 'name')
|
||||
->searchable()
|
||||
->preload(),
|
||||
|
||||
Tables\Filters\SelectFilter::make('class_id')
|
||||
->label('Class')
|
||||
->relationship('class', 'class_name')
|
||||
->searchable()
|
||||
->preload(),
|
||||
|
||||
])
|
||||
->actions([
|
||||
Tables\Actions\EditAction::make(),
|
||||
Tables\Actions\DeleteAction::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\ListTeacherSubjects::route('/'),
|
||||
'create' => Pages\CreateTeacherSubject::route('/create'),
|
||||
'edit' => Pages\EditTeacherSubject::route('/{record}/edit'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\TeacherSubjectResource\Pages;
|
||||
|
||||
use App\Filament\Resources\TeacherSubjectResource;
|
||||
use App\Models\TeacherSubject;
|
||||
use Filament\Actions;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
class CreateTeacherSubject extends CreateRecord
|
||||
{
|
||||
protected static string $resource = TeacherSubjectResource::class;
|
||||
|
||||
protected function mutateFormDataBeforeCreate(array $data): array
|
||||
{
|
||||
$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'])
|
||||
->exists();
|
||||
|
||||
if ($exists) {
|
||||
Notification::make()
|
||||
->title('Failed to save')
|
||||
->body('The combination of teacher, subject, class, and academic year is already registered.')
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
$this->halt();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\TeacherSubjectResource\Pages;
|
||||
|
||||
use App\Filament\Resources\TeacherSubjectResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
|
||||
class EditTeacherSubject extends EditRecord
|
||||
{
|
||||
protected static string $resource = TeacherSubjectResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\DeleteAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\TeacherSubjectResource\Pages;
|
||||
|
||||
use App\Filament\Resources\TeacherSubjectResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListTeacherSubjects extends ListRecords
|
||||
{
|
||||
protected static string $resource = TeacherSubjectResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\CreateAction::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
26
app/Models/Attendances.php
Normal file
26
app/Models/Attendances.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Attendances extends Model
|
||||
{
|
||||
protected $fillable = ['student_id', 'teacher_subject_id', 'date', 'status', 'recorded_by', 'semester', 'notes'];
|
||||
|
||||
public function student()
|
||||
{
|
||||
return $this->belongsTo(Student::class, 'student_id');
|
||||
}
|
||||
|
||||
public function teacherSubject()
|
||||
{
|
||||
return $this->belongsTo(TeacherSubject::class, 'teacher_subject_id');
|
||||
}
|
||||
|
||||
// Relasi dengan guru yang merekam
|
||||
public function recorder()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'recorded_by');
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,7 @@
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class ClassRoom extends Model
|
||||
{
|
||||
@ -22,4 +23,9 @@ class ClassRoom extends Model
|
||||
{
|
||||
return $this->hasMany(Student::class, 'class_id');
|
||||
}
|
||||
|
||||
public function teacherAssignments(): HasMany
|
||||
{
|
||||
return $this->hasMany(TeacherSubject::class, 'class_id');
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,5 +6,5 @@ use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Extracurricular extends Model
|
||||
{
|
||||
protected $fillable = ['name', 'description',];
|
||||
protected $fillable = ['name', 'description'];
|
||||
}
|
||||
|
||||
@ -8,17 +8,18 @@ class Student extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'nis',
|
||||
'nisn',
|
||||
'full_name',
|
||||
'gender',
|
||||
'birth_date',
|
||||
'birth_place',
|
||||
'address',
|
||||
'religion',
|
||||
'phone',
|
||||
'email',
|
||||
'class_id',
|
||||
'parent_name',
|
||||
'parent_phone',
|
||||
'profile_picture'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class Subject extends Model
|
||||
{
|
||||
@ -13,6 +14,12 @@ class Subject extends Model
|
||||
return $this->hasMany(SubjectScope::class);
|
||||
}
|
||||
|
||||
public function teacherAssignments(): HasMany
|
||||
{
|
||||
return $this->hasMany(TeacherSubject::class, 'subject_id');
|
||||
}
|
||||
|
||||
|
||||
// public function grades()
|
||||
// {
|
||||
// return $this->hasMany(Grade::class);
|
||||
|
||||
56
app/Models/TeacherSubject.php
Normal file
56
app/Models/TeacherSubject.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class TeacherSubject extends Model
|
||||
{
|
||||
protected $fillable = ['teacher_id', 'subject_id', 'class_id', 'academic_year'];
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@ -4,6 +4,7 @@ namespace App\Models;
|
||||
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Spatie\Permission\Traits\HasRoles;
|
||||
@ -51,4 +52,9 @@ class User extends Authenticatable
|
||||
'password' => 'hashed',
|
||||
];
|
||||
}
|
||||
|
||||
public function teacherSubjects(): HasMany
|
||||
{
|
||||
return $this->hasMany(TeacherSubject::class, 'teacher_id');
|
||||
}
|
||||
}
|
||||
|
||||
@ -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('teacher_subjects', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('teacher_id')->constrained('users');
|
||||
$table->foreignId('subject_id')->constrained('subjects');
|
||||
$table->foreignId('class_id')->constrained('class_rooms');
|
||||
$table->string('academic_year');
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['teacher_id', 'subject_id', 'class_id', 'academic_year']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('teacher_subjects');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,36 @@
|
||||
<?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('attendances', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('teacher_subject_id')->nullable()->constrained('teacher_subjects');
|
||||
$table->foreignId('student_id')->constrained('students');
|
||||
$table->date('date');
|
||||
$table->enum('status', ['present', 'absent', 'permission', 'sick']);
|
||||
$table->foreignId('recorded_by')->constrained('users');
|
||||
$table->string('semester');
|
||||
$table->text('notes')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['teacher_subject_id', 'student_id', 'date', 'semester']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('attendances');
|
||||
}
|
||||
};
|
||||
28
database/seeders/AssessmentComponentSeeder.php
Normal file
28
database/seeders/AssessmentComponentSeeder.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\AssessmentComponent;
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class AssessmentComponentSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$components = [
|
||||
['name' => 'Ulangan Harian', 'code' => 'UH', 'weight' => 20, 'is_active' => true],
|
||||
['name' => 'Penilaian Tengah Semester', 'code' => 'PTS', 'weight' => 20, 'is_active' => true],
|
||||
['name' => 'Penilaian Akhir Semester', 'code' => 'PAS', 'weight' => 30, 'is_active' => true],
|
||||
['name' => 'Absensi', 'code' => 'ABS', 'weight' => 20, 'is_active' => true],
|
||||
['name' => 'Ekstrakurikuler', 'code' => 'EKS', 'weight' => 10, 'is_active' => true],
|
||||
];
|
||||
|
||||
foreach ($components as $component) {
|
||||
AssessmentComponent::create($component);
|
||||
}
|
||||
}
|
||||
}
|
||||
17
database/seeders/AttendanceSeeder.php
Normal file
17
database/seeders/AttendanceSeeder.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?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
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
32
database/seeders/ClassRoomSeeder.php
Normal file
32
database/seeders/ClassRoomSeeder.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\ClassRoom;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
class ClassRoomSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$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'],
|
||||
];
|
||||
|
||||
foreach ($classes as $index => $class) {
|
||||
$class['homeroom_teacher_id'] = $teachers[$index % count($teachers)]->id;
|
||||
ClassRoom::create($class);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -15,44 +15,14 @@ class DatabaseSeeder extends Seeder
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// 1. Buat user admin jika belum ada
|
||||
$admin = User::firstOrCreate(
|
||||
['email' => 'admin@example.com'],
|
||||
[
|
||||
'name' => 'admin',
|
||||
'password' => bcrypt('admin'),
|
||||
]
|
||||
);
|
||||
|
||||
// 2. Buat permission terkait role satu per satu
|
||||
Permission::firstOrCreate(['name' => 'view_any_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'view_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'create_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'update_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'delete_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'delete_any_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'force_delete_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'force_delete_any_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'restore_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'restore_any_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'replicate_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'reorder_role', 'guard_name' => 'web']);
|
||||
|
||||
// 3. Ambil semua permission yang berhubungan dengan "_role"
|
||||
$rolePermissions = Permission::where('name', 'like', '%_role')->pluck('name');
|
||||
|
||||
// 4. Buat role super_admin jika belum ada
|
||||
$role = Role::firstOrCreate([
|
||||
'name' => 'super_admin',
|
||||
'guard_name' => 'web',
|
||||
$this->call([
|
||||
UserSeeder::class,
|
||||
SubjectSeeder::class,
|
||||
ClassRoomSeeder::class,
|
||||
StudentSeeder::class,
|
||||
ExtracurricularSeeder::class,
|
||||
AssessmentComponentSeeder::class,
|
||||
AttendanceSeeder::class,
|
||||
]);
|
||||
|
||||
// 5. Assign semua permission "_role" ke super_admin
|
||||
$role->syncPermissions($rolePermissions);
|
||||
|
||||
// 6. Assign role super_admin ke user admin
|
||||
if (!$admin->hasRole($role)) {
|
||||
$admin->assignRole($role);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
26
database/seeders/ExtracurricularSeeder.php
Normal file
26
database/seeders/ExtracurricularSeeder.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Extracurricular;
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class ExtracurricularSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$extracurriculars = [
|
||||
['name' => 'Pramuka', 'description' => 'Kegiatan kepramukaan'],
|
||||
['name' => 'Basket', 'description' => 'Ekstrakurikuler basket'],
|
||||
['name' => 'Futsal', 'description' => 'Ekstrakurikuler futsal'],
|
||||
];
|
||||
|
||||
foreach ($extracurriculars as $extracurricular) {
|
||||
Extracurricular::create($extracurricular);
|
||||
}
|
||||
}
|
||||
}
|
||||
44
database/seeders/StudentSeeder.php
Normal file
44
database/seeders/StudentSeeder.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\ClassRoom;
|
||||
use App\Models\Student;
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class StudentSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
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);
|
||||
|
||||
Student::firstOrCreate(
|
||||
['nis' => $nis], // Cek berdasarkan NIS
|
||||
[
|
||||
'full_name' => 'Siswa ' . $classroom->class_name . ' ' . $i,
|
||||
'gender' => $gender,
|
||||
'birth_date' => 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),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
17
database/seeders/SubjectScopeSeeder.php
Normal file
17
database/seeders/SubjectScopeSeeder.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class SubjectScopeSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
55
database/seeders/SubjectSeeder.php
Normal file
55
database/seeders/SubjectSeeder.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Subject;
|
||||
use App\Models\SubjectScope;
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class SubjectSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
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],
|
||||
];
|
||||
|
||||
foreach ($subjects as $subject) {
|
||||
$createdSubject = Subject::create($subject);
|
||||
|
||||
// Untuk mata pelajaran agama, buat scope
|
||||
if (str_contains($createdSubject->name, 'Agama')) {
|
||||
$religion = match(true) {
|
||||
str_contains($createdSubject->name, 'Islam') => 'islam',
|
||||
str_contains($createdSubject->name, 'Kristen') => 'kristen',
|
||||
str_contains($createdSubject->name, 'Katolik') => 'katolik',
|
||||
str_contains($createdSubject->name, 'Hindu') => 'hindu',
|
||||
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'
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
75
database/seeders/UserSeeder.php
Normal file
75
database/seeders/UserSeeder.php
Normal file
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
class UserSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// 1. Buat user admin jika belum ada
|
||||
$admin = User::firstOrCreate(
|
||||
['email' => 'admin@example.com'],
|
||||
[
|
||||
'name' => 'admin',
|
||||
'password' => bcrypt('admin'),
|
||||
]
|
||||
);
|
||||
|
||||
$user = User::firstOrCreate(
|
||||
['email' => 'teacher@example.com'],
|
||||
[
|
||||
'name' => 'teacher',
|
||||
'password' => bcrypt('teacher'),
|
||||
]
|
||||
);
|
||||
|
||||
// 2. Buat permission terkait role satu per satu
|
||||
Permission::firstOrCreate(['name' => 'view_any_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'view_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'create_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'update_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'delete_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'delete_any_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'force_delete_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'force_delete_any_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'restore_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'restore_any_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'replicate_role', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'reorder_role', 'guard_name' => 'web']);
|
||||
|
||||
// 3. Ambil semua permission yang berhubungan dengan "_role"
|
||||
$rolePermissions = Permission::where('name', 'like', '%_role')->pluck('name');
|
||||
|
||||
// 4. Buat role super_admin jika belum ada
|
||||
$role = Role::firstOrCreate([
|
||||
'name' => 'super_admin',
|
||||
'guard_name' => 'web',
|
||||
]);
|
||||
|
||||
$teacher = Role::firstOrCreate([
|
||||
'name' => 'teacher',
|
||||
'guard_name' => 'web',
|
||||
]);
|
||||
|
||||
$teacher->syncPermissions($rolePermissions);
|
||||
|
||||
$role->syncPermissions($rolePermissions);
|
||||
|
||||
if (!$admin->hasRole($role)) {
|
||||
$admin->assignRole($role);
|
||||
}
|
||||
|
||||
if (!$user->hasRole($teacher)) {
|
||||
$user->assignRole($teacher);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
<x-filament-panels::page>
|
||||
<x-filament-panels::form wire:submit="submit">
|
||||
{{ $this->form }}
|
||||
|
||||
@if($this->attendanceDate && $this->teacherSubjectId)
|
||||
<div class="mt-6 space-y-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="text-lg font-medium">Student Attendance</h3>
|
||||
<div class="flex gap-2 space-x-2">
|
||||
<x-filament::button type="button" wire:click="markAll('present')" color="success">
|
||||
Mark All Present
|
||||
</x-filament::button>
|
||||
<x-filament::button type="button" wire:click="markAll('absent')" color="danger">
|
||||
Mark All Absent
|
||||
</x-filament::button>
|
||||
<x-filament::button type="button" wire:click="markAll('sick')" color="warning">
|
||||
Mark All Sick
|
||||
</x-filament::button>
|
||||
<x-filament::button type="button" wire:click="markAll('permission')" color="warning">
|
||||
Mark All Permission
|
||||
</x-filament::button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
@foreach($this->students as $index => $student)
|
||||
<div class="flex items-center p-3 border rounded-lg">
|
||||
<div class="flex-1 flex items-center gap-4">
|
||||
<p class="font-medium">{{ $student['name'] }}</p>
|
||||
<p class="text-sm text-gray-500">{{ $student['nis'] }}</p>
|
||||
</div>
|
||||
<div class="flex gap-2 space-x-2">
|
||||
<x-filament::button
|
||||
type="button"
|
||||
wire:click="$set('students.{{ $index }}.status', 'present')"
|
||||
color="{{ $student['status'] === 'present' ? 'success' : 'gray' }}"
|
||||
size="sm"
|
||||
>
|
||||
Present
|
||||
</x-filament::button>
|
||||
<x-filament::button
|
||||
type="button"
|
||||
wire:click="$set('students.{{ $index }}.status', 'absent')"
|
||||
color="{{ $student['status'] === 'absent' ? 'danger' : 'gray' }}"
|
||||
size="sm"
|
||||
>
|
||||
Absent
|
||||
</x-filament::button>
|
||||
<x-filament::button
|
||||
type="button"
|
||||
wire:click="$set('students.{{ $index }}.status', 'sick')"
|
||||
color="{{ $student['status'] === 'sick' ? 'warning' : 'gray' }}"
|
||||
size="sm"
|
||||
>
|
||||
Sick
|
||||
</x-filament::button>
|
||||
<x-filament::button
|
||||
type="button"
|
||||
wire:click="$set('students.{{ $index }}.status', 'permission')"
|
||||
color="{{ $student['status'] === 'permission' ? 'warning' : 'gray' }}"
|
||||
size="sm"
|
||||
>
|
||||
Permission
|
||||
</x-filament::button>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<x-filament::button type="submit" class="w-full">
|
||||
Save Attendance
|
||||
</x-filament::button>
|
||||
</div>
|
||||
@endif
|
||||
</x-filament-panels::form>
|
||||
</x-filament-panels::page>
|
||||
Loading…
x
Reference in New Issue
Block a user