Merge pull request #5 from reihanrere/add-role-parent

add-page-parent
This commit is contained in:
Reihan Renaldi 2025-05-25 11:14:23 +07:00 committed by GitHub
commit f057b0c283
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 187 additions and 115 deletions

View File

@ -24,12 +24,12 @@ class SchoolInformation extends Page implements HasForms
public static function canAccess(): bool public static function canAccess(): bool
{ {
return auth()->user()->hasAnyRole(['super_admin']); return auth()->user()?->can('page_SchoolInformation');
} }
public static function shouldRegisterNavigation(): bool public static function shouldRegisterNavigation(): bool
{ {
return auth()->user()->hasAnyRole(['super_admin']); return auth()->user()?->can('page_SchoolInformation');
} }
public ?array $data = []; public ?array $data = [];

View File

@ -34,25 +34,29 @@ class StudentReport extends Page
public static function canAccess(): bool public static function canAccess(): bool
{ {
$user = auth()->user(); $user = auth()->user();
$isTeacher = false;
$homeRoomTeacher = HomeRoomTeacher::where('teacher_id', $user->id)->first(); if ($user->hasRole('parent')) {
if ($homeRoomTeacher) { return true;
$isTeacher = true;
} }
return auth()->user()->hasAnyRole(['super_admin']) || auth()->user()->hasAnyRole(['headmaster']) || $isTeacher; $isHomeRoomTeacher = HomeRoomTeacher::where('teacher_id', $user->id)->exists();
return $user->can('page_SchoolInformation') || $isHomeRoomTeacher;
} }
public static function shouldRegisterNavigation(): bool public static function shouldRegisterNavigation(): bool
{ {
$user = auth()->user(); $user = auth()->user();
$isTeacher = false;
$homeRoomTeacher = HomeRoomTeacher::where('teacher_id', $user->id)->first(); if ($user->hasRole('parent')) {
if ($homeRoomTeacher) { return true;
$isTeacher = true;
} }
return auth()->user()->hasAnyRole(['super_admin']) || auth()->user()->hasAnyRole(['headmaster']) || $isTeacher; // Untuk teacher (wali kelas)
$isHomeRoomTeacher = HomeRoomTeacher::where('teacher_id', $user->id)->exists();
// Atau punya permission khusus
return $user->can('page_SchoolInformation') || $isHomeRoomTeacher;
} }
public function mount(): void public function mount(): void
@ -66,17 +70,6 @@ class StudentReport extends Page
public function form(Form $form): Form public function form(Form $form): Form
{ {
return $form->schema([ 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('class_id') Select::make('class_id')
->label('Class') ->label('Class')
->required() ->required()
@ -90,6 +83,17 @@ class StudentReport extends Page
if ($homeRoomTeacher) { if ($homeRoomTeacher) {
$query->where('id', $homeRoomTeacher->class_room_id); $query->where('id', $homeRoomTeacher->class_room_id);
} }
} else if ($user->hasAnyRole(['parent'])) {
$student = Student::where("email", $user->email)->first(); // Changed from student email to parent_email
if ($student) {
$classStudentIds = ClassStudent::where("student_id", $student->id)
->pluck('class_room_id')
->toArray();
$query->whereIn("id", $classStudentIds);
}
} }
return $query->pluck('class_name', 'id')->toArray(); return $query->pluck('class_name', 'id')->toArray();
@ -137,6 +141,15 @@ class StudentReport extends Page
return; return;
} }
$user = auth()->user();
$isParent = $user->hasRole('parent');
$studentId = null;
if ($isParent) {
$student = Student::where('email', $user->email)->first();
$studentId = $student->id ?? null;
}
$groupedAssessment = []; $groupedAssessment = [];
$assessments = Assessment::where('semester', $this->semester) $assessments = Assessment::where('semester', $this->semester)
@ -144,6 +157,9 @@ class StudentReport extends Page
$query->where('academic_year_id', $this->academic_year) $query->where('academic_year_id', $this->academic_year)
->where('class_id', $this->class_id); ->where('class_id', $this->class_id);
}) })
->when($isParent && $studentId, function($query) use ($studentId) {
$query->where('student_id', $studentId); // Tambahan filter untuk parent
})
->with('teacherSubject', 'student') ->with('teacherSubject', 'student')
->get() ->get()
->toArray(); ->toArray();
@ -170,6 +186,9 @@ class StudentReport extends Page
$students = ClassStudent::with(['class', 'academicYear', 'student']) $students = ClassStudent::with(['class', 'academicYear', 'student'])
->where('class_room_id', $this->class_id) ->where('class_room_id', $this->class_id)
->where('academic_year_id', $this->academic_year) ->where('academic_year_id', $this->academic_year)
->when($isParent && $studentId, function($query) use ($studentId) {
$query->where('student_id', $studentId); // Tambahan filter untuk parent
})
->get() ->get()
->map(function($student) { ->map(function($student) {
return $student['student']; return $student['student'];

View File

@ -171,7 +171,7 @@ class AssessmentResource extends Resource
]) ])
->bulkActions([ ->bulkActions([
Tables\Actions\BulkActionGroup::make([ Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make()->visible(fn () => auth()->user()->hasRole('super_admin') || auth()->user()->hasRole('teacher')), Tables\Actions\DeleteBulkAction::make()->visible(fn () => auth()->user()->hasRole('admin') || auth()->user()->hasRole('teacher')),
]), ]),
]) ])
->emptyStateActions([ ->emptyStateActions([

View File

@ -34,12 +34,12 @@ class ListAssessments extends ListRecords
protected function getHeaderActions(): array protected function getHeaderActions(): array
{ {
return [ return [
Actions\CreateAction::make()->visible(fn () => auth()->user()->hasRole('super_admin')), Actions\CreateAction::make()->visible(fn () => auth()->user()->hasRole('admin')),
Actions\Action::make('multiple') Actions\Action::make('multiple')
->label('Multiple Assessments') ->label('Multiple Assessments')
->url('assessments/multiple') ->url('assessments/multiple')
->icon('heroicon-o-user-group') ->icon('heroicon-o-user-group')
->visible(fn () => auth()->user()->hasRole('super_admin') || auth()->user()->hasRole('teacher')), ->visible(fn () => auth()->user()->hasRole('admin') || auth()->user()->hasRole('teacher')),
]; ];
} }
} }

View File

@ -240,7 +240,7 @@ class AttendancesResource extends Resource
]) ])
->bulkActions([ ->bulkActions([
Tables\Actions\BulkActionGroup::make([ Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make()->visible(fn () => auth()->user()->hasRole('super_admin') || auth()->user()->hasRole('teacher')), Tables\Actions\DeleteBulkAction::make()->visible(fn () => auth()->user()->hasRole('admin') || auth()->user()->hasRole('teacher')),
]), ]),
]) ])
->defaultSort('date', 'desc') ->defaultSort('date', 'desc')

View File

@ -34,12 +34,12 @@ class ListAttendances extends ListRecords
protected function getHeaderActions(): array protected function getHeaderActions(): array
{ {
return [ return [
Actions\CreateAction::make()->visible(fn () => auth()->user()->hasRole('super_admin')), Actions\CreateAction::make()->visible(fn () => auth()->user()->hasRole('admin')),
Actions\Action::make('multiple') Actions\Action::make('multiple')
->label('Multiple Attendance') ->label('Multiple Attendance')
->url('attendances/multiple') ->url('attendances/multiple')
->icon('heroicon-o-user-group') ->icon('heroicon-o-user-group')
->visible(fn () => auth()->user()->hasRole('super_admin') || auth()->user()->hasRole('teacher')), ->visible(fn () => auth()->user()->hasRole('admin') || auth()->user()->hasRole('teacher')),
]; ];
} }
} }

View File

@ -101,7 +101,7 @@ class CompetencyAchievementResource extends Resource
]) ])
->bulkActions([ ->bulkActions([
Tables\Actions\BulkActionGroup::make([ Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make()->visible(fn () => auth()->user()->hasRole('super_admin') || auth()->user()->hasRole('teacher')), Tables\Actions\DeleteBulkAction::make()->visible(fn () => auth()->user()->hasRole('admin') || auth()->user()->hasRole('teacher')),
]), ]),
]) ])
->emptyStateActions([ ->emptyStateActions([

View File

@ -32,7 +32,7 @@ class ExtracurricularAssessmentResource extends Resource
$user = auth()->user(); $user = auth()->user();
$query = ClassStudent::with(['student', 'class']); $query = ClassStudent::with(['student', 'class']);
if ($user->hasAnyRole(['super_admin'])) if ($user->hasAnyRole(['admin']))
{ {
return $query->get()->mapWithKeys(function ($cs) { return $query->get()->mapWithKeys(function ($cs) {
return [ return [
@ -125,7 +125,7 @@ class ExtracurricularAssessmentResource extends Resource
]) ])
->bulkActions([ ->bulkActions([
Tables\Actions\BulkActionGroup::make([ Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make()->visible(fn () => auth()->user()->hasRole('super_admin') || auth()->user()->hasRole('teacher')), Tables\Actions\DeleteBulkAction::make()->visible(fn () => auth()->user()->hasRole('admin') || auth()->user()->hasRole('teacher')),
]), ]),
]) ])
->emptyStateActions([ ->emptyStateActions([

View File

@ -62,8 +62,9 @@ class StudentResource extends Resource
->maxLength(15), ->maxLength(15),
Forms\Components\TextInput::make('email') Forms\Components\TextInput::make('email')
->label('Email') ->label("Parent's Email")
->email() ->email()
->required()
->maxLength(100), ->maxLength(100),
Forms\Components\TextInput::make('parent_name') Forms\Components\TextInput::make('parent_name')
@ -73,6 +74,7 @@ class StudentResource extends Resource
Forms\Components\TextInput::make('parent_phone') Forms\Components\TextInput::make('parent_phone')
->label("Parent's Phone") ->label("Parent's Phone")
->required()
->maxLength(15), ->maxLength(15),
Forms\Components\Select::make('religion') Forms\Components\Select::make('religion')

View File

@ -5,51 +5,34 @@ namespace App\Filament\Resources\StudentResource\Pages;
use App\Filament\Resources\StudentResource; use App\Filament\Resources\StudentResource;
use App\Models\Student; use App\Models\Student;
use App\Models\User; use App\Models\User;
use Carbon\Carbon;
use Filament\Actions; use Filament\Actions;
use Filament\Notifications\Notification; use Filament\Notifications\Notification;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
use Spatie\Permission\Models\Role;
class CreateStudent extends CreateRecord class CreateStudent extends CreateRecord
{ {
protected static string $resource = StudentResource::class; protected static string $resource = StudentResource::class;
// protected function mutateFormDataBeforeCreate(array $data): array protected function mutateFormDataBeforeCreate(array $data): array
// { {
//// $user = User::firstOrCreate( $parentRole = Role::where('name', 'parent')->first();
//// ['email' => 'teacher@example.com'],
//// [ $birthDate = Carbon::parse($data['birth_date']);
//// 'name' => 'teacher', $password = $birthDate->format('dmY') . $data['nis'];
//// 'password' => bcrypt('teacher'),
//// ] $parentUser = User::updateOrCreate(
//// ); ['email' => $data['email']],
//// [
// $birthDate = explode('-', $data['birth_date']); 'name' => $data['parent_name'],
// 'password' => bcrypt($password),
// 'phone' => $data['parent_phone'],
// $password = join("", $birthDate) . '-' . $data['nis']; ]
// );
// $add = [
// 'email' => $data['email'], $parentUser->assignRole($parentRole);
// 'name' => $data['parent_name'],
// 'password' => $password, return $data;
// ]; }
//
// dd($add);
// die;
//
// $exists = Student::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

@ -3,17 +3,47 @@
namespace App\Filament\Resources\StudentResource\Pages; namespace App\Filament\Resources\StudentResource\Pages;
use App\Filament\Resources\StudentResource; use App\Filament\Resources\StudentResource;
use App\Models\User;
use Filament\Actions; use Filament\Actions;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\EditRecord; use Filament\Resources\Pages\EditRecord;
use Spatie\Permission\Models\Role;
class EditStudent extends EditRecord class EditStudent extends EditRecord
{ {
protected static string $resource = StudentResource::class; protected static string $resource = StudentResource::class;
protected function mutateFormDataBeforeSave(array $data): array
{
$parentRole = Role::where('name', 'parent')->first();
$parentUser = User::updateOrCreate(
['email' => $data['email']],
[
'name' => $data['parent_name'],
'phone' => $data['parent_phone'],
]
);
// Pastikan user memiliki role parent
if (!$parentUser->hasRole('parent')) {
$parentUser->assignRole($parentRole);
}
return $data;
}
protected function getHeaderActions(): array protected function getHeaderActions(): array
{ {
return [ return [
Actions\DeleteAction::make(), Actions\DeleteAction::make()
->before(function (Actions\DeleteAction $action) {
$student = $this->record;
if ($student->email) {
User::where('email', $student->email)->delete();
}
}),
]; ];
} }
} }

View File

@ -83,12 +83,12 @@ class UserResource extends Resource
Tables\Columns\TextColumn::make('gender') Tables\Columns\TextColumn::make('gender')
->formatStateUsing(fn (string $state): string => ucfirst($state)), ->formatStateUsing(fn (string $state): string => ucfirst($state)),
Tables\Columns\TextColumn::make('birth_date') Tables\Columns\TextColumn::make('birth_date')
->date() ->date(),
->sortable(),
Tables\Columns\TextColumn::make('phone') Tables\Columns\TextColumn::make('phone')
->searchable(), ->searchable(),
Tables\Columns\TextColumn::make('roles.name') Tables\Columns\TextColumn::make('roles.name')
->searchable(), ->searchable()
->sortable(),
Tables\Columns\TextColumn::make('created_at') Tables\Columns\TextColumn::make('created_at')
->dateTime() ->dateTime()
->sortable() ->sortable()
@ -102,11 +102,11 @@ class UserResource extends Resource
// //
]) ])
->actions([ ->actions([
Tables\Actions\EditAction::make()->visible(fn () => auth()->user()->hasRole('super_admin')), Tables\Actions\EditAction::make()->visible(fn () => auth()->user()->hasRole('admin')),
]) ])
->bulkActions([ ->bulkActions([
Tables\Actions\BulkActionGroup::make([ Tables\Actions\BulkActionGroup::make([
// Tables\Actions\DeleteBulkAction::make()->visible(fn () => auth()->user()->hasRole('super_admin')), // Tables\Actions\DeleteBulkAction::make()->visible(fn () => auth()->user()->hasRole('admin')),
]), ]),
]) ])
->emptyStateActions([ ->emptyStateActions([

View File

@ -13,7 +13,7 @@ class SchoolInformationPolicy
*/ */
public function viewAny(User $user): bool public function viewAny(User $user): bool
{ {
return $user->can('view_any_school::information'); return $user->can('page_SchoolInformation');
} }
/** /**
@ -21,7 +21,7 @@ class SchoolInformationPolicy
*/ */
public function view(User $user, SchoolInformation $schoolInformation): bool public function view(User $user, SchoolInformation $schoolInformation): bool
{ {
return $user->can('view_school::information'); return $user->can('page_SchoolInformation');
} }
/** /**
@ -29,7 +29,7 @@ class SchoolInformationPolicy
*/ */
public function create(User $user): bool public function create(User $user): bool
{ {
return $user->can('create_school::information'); return $user->can('page_SchoolInformation');
} }
/** /**
@ -37,7 +37,7 @@ class SchoolInformationPolicy
*/ */
public function update(User $user, SchoolInformation $schoolInformation): bool public function update(User $user, SchoolInformation $schoolInformation): bool
{ {
return $user->can('update_school::information'); return $user->can('page_SchoolInformation');
} }
/** /**
@ -45,7 +45,7 @@ class SchoolInformationPolicy
*/ */
public function delete(User $user, SchoolInformation $schoolInformation): bool public function delete(User $user, SchoolInformation $schoolInformation): bool
{ {
return $user->can('delete_school::information'); return $user->can('page_SchoolInformation');
} }
/** /**
@ -53,7 +53,7 @@ class SchoolInformationPolicy
*/ */
public function restore(User $user, SchoolInformation $schoolInformation): bool public function restore(User $user, SchoolInformation $schoolInformation): bool
{ {
return $user->can('restore_school::information'); return $user->can('page_SchoolInformation');
} }
/** /**
@ -61,6 +61,6 @@ class SchoolInformationPolicy
*/ */
public function forceDelete(User $user, SchoolInformation $schoolInformation): bool public function forceDelete(User $user, SchoolInformation $schoolInformation): bool
{ {
return $user->can('force_delete_school::information'); return $user->can('page_SchoolInformation');
} }
} }

View File

@ -21,7 +21,7 @@ return [
'super_admin' => [ 'super_admin' => [
'enabled' => true, 'enabled' => true,
'name' => 'super_admin', 'name' => 'admin',
'define_via_gate' => false, 'define_via_gate' => false,
'intercept_gate' => 'before', // after 'intercept_gate' => 'before', // after
], ],

View File

@ -6,34 +6,45 @@ use App\Models\AcademicYear;
use App\Models\ClassRoom; use App\Models\ClassRoom;
use App\Models\ClassStudent; use App\Models\ClassStudent;
use App\Models\Student; use App\Models\Student;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder; use Illuminate\Database\Seeder;
class ClassStudentSeeder extends Seeder class ClassStudentSeeder extends Seeder
{ {
/**
* Run the database seeds.
*/
public function run(): void public function run(): void
{ {
// Pastikan data ClassRoom, Student, dan AcademicYear sudah ada $academicYears = AcademicYear::all();
$classRooms = ClassRoom::all(); $classRooms = ClassRoom::all();
$students = Student::all(); $students = Student::all();
$academicYears = AcademicYear::all();
// Hanya melanjutkan jika data tersedia // Pastikan ada data yang tersedia
if ($classRooms->isNotEmpty() && $students->isNotEmpty() && $academicYears->isNotEmpty()) { if ($academicYears->isEmpty() || $classRooms->isEmpty() || $students->isEmpty()) {
foreach ($classRooms as $classRoom) { return;
foreach ($students as $student) { }
// Distribusikan siswa ke kelas secara merata
$studentsPerClass = ceil($students->count() / $classRooms->count());
$studentChunks = $students->chunk($studentsPerClass);
foreach ($academicYears as $academicYear) { foreach ($academicYears as $academicYear) {
// Buat ClassStudent baru untuk setiap kombinasi $classIndex = 0;
ClassStudent::create([
foreach ($studentChunks as $studentGroup) {
// Pastikan kita tidak melebihi jumlah kelas yang tersedia
if ($classIndex >= $classRooms->count()) {
break;
}
$classRoom = $classRooms[$classIndex];
foreach ($studentGroup as $student) {
ClassStudent::firstOrCreate([
'class_room_id' => $classRoom->id, 'class_room_id' => $classRoom->id,
'student_id' => $student->id, 'student_id' => $student->id,
'academic_year_id' => $academicYear->id, 'academic_year_id' => $academicYear->id,
]); ]);
} }
}
$classIndex++;
} }
} }
} }

View File

@ -2,38 +2,55 @@
namespace Database\Seeders; namespace Database\Seeders;
use App\Models\ClassRoom;
use App\Models\Student; use App\Models\Student;
use App\Models\User;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder; use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;
class StudentSeeder extends Seeder class StudentSeeder extends Seeder
{ {
/**
* Run the database seeds.
*/
public function run(): void public function run(): void
{ {
$religions = ['islam', 'kristen', 'katolik', 'hindu', 'buddha']; $religions = ['islam', 'kristen', 'katolik', 'hindu', 'buddha'];
$parentRole = Role::where('name', 'parent')->firstOrFail();
for ($i = 1; $i <= 20; $i++) { for ($i = 1; $i <= 20; $i++) {
$gender = $i % 2 == 0 ? 'L' : 'P'; $gender = $i % 2 == 0 ? 'L' : 'P';
$religion = $religions[array_rand($religions)]; $religion = $religions[array_rand($religions)];
$nis = '24' . str_pad($i, 4, '0', STR_PAD_LEFT); // NIS unik, misal 240001 $nis = '24' . str_pad($i, 4, '0', STR_PAD_LEFT);
$birthDate = Carbon::now()->subYears(rand(15, 18))->subMonths(rand(1, 12));
$parentName = 'Orang Tua Siswa ' . $i;
$parentEmail = 'parent' . $i . '@example.com';
$parentPhone = '0813' . rand(1000000, 9999999);
$birthDateParse = Carbon::parse($birthDate);
$password = $birthDateParse->format('dmY') . $nis;
$parentUser = User::firstOrCreate(
['email' => $parentEmail],
[
'name' => $parentName,
'password' => bcrypt($password),
'phone' => $parentPhone,
]
);
$parentUser->assignRole($parentRole);
Student::firstOrCreate( Student::firstOrCreate(
['nis' => $nis], // Cek berdasarkan NIS ['nis' => $nis],
[ [
'full_name' => 'Siswa ' . $i, 'full_name' => 'Siswa ' . $i,
'gender' => $gender, 'gender' => $gender,
'birth_date' => Carbon::now()->subYears(rand(15, 18))->subMonths(rand(1, 12)), 'birth_date' => $birthDate,
'birth_place' => 'Kota ' . chr(65 + rand(0, 25)), 'birth_place' => 'Kota ' . chr(65 + rand(0, 25)),
'address' => 'Jl. Contoh No.' . $i, 'address' => 'Jl. Contoh No.' . $i,
'phone' => '0812' . rand(1000000, 9999999), 'phone' => '0812' . rand(1000000, 9999999),
'parent_name' => 'Orang Tua Siswa ' . $i, 'parent_name' => $parentName,
'religion' => $religion, 'religion' => $religion,
'parent_phone' => '0813' . rand(1000000, 9999999), 'parent_phone' => $parentPhone,
'email' => $parentEmail,
'created_at' => now(), 'created_at' => now(),
'updated_at' => now(), 'updated_at' => now(),
] ]

View File

@ -51,7 +51,7 @@ class UserSeeder extends Seeder
// 4. Buat role super_admin jika belum ada // 4. Buat role super_admin jika belum ada
$role = Role::firstOrCreate([ $role = Role::firstOrCreate([
'name' => 'super_admin', 'name' => 'admin',
'guard_name' => 'web', 'guard_name' => 'web',
]); ]);
@ -60,6 +60,16 @@ class UserSeeder extends Seeder
'guard_name' => 'web', 'guard_name' => 'web',
]); ]);
$headmaster = Role::firstOrCreate([
'name' => 'headmaster',
'guard_name' => 'web',
]);
$parent = Role::firstOrCreate([
'name' => 'parent',
'guard_name' => 'web',
]);
$teacher->syncPermissions($rolePermissions); $teacher->syncPermissions($rolePermissions);
$role->syncPermissions($rolePermissions); $role->syncPermissions($rolePermissions);